sql >> Database >  >> RDS >> Sqlserver

De beste manier om XML-gegevens te versnipperen in SQL Server-databasekolommen

Ik kwam deze vraag tegen terwijl ik een vergelijkbaar probleem had. Ik had een query uitgevoerd die een XML-bestand van 7,5 MB (ca. 10.000 nodes) ongeveer 3,5 tot 4 uur verwerkte voordat ik het uiteindelijk opgaf.

Na wat meer onderzoek ontdekte ik echter dat nadat ik de XML had getypt met behulp van een schema en een XML-index had gemaakt (ik had deze in bulk in een tabel ingevoegd), dezelfde query voltooid in ~ 0,04 ms.

Hoe is dat voor een prestatieverbetering!

Code om een ​​schema te maken:

IF EXISTS ( SELECT * FROM sys.xml_schema_collections where [name] = 'MyXmlSchema')
DROP XML SCHEMA COLLECTION [MyXmlSchema]
GO

DECLARE @MySchema XML
SET @MySchema = 
(
    SELECT * FROM OPENROWSET
    (
        BULK 'C:\Path\To\Schema\MySchema.xsd', SINGLE_CLOB 
    ) AS xmlData
)

CREATE XML SCHEMA COLLECTION [MyXmlSchema] AS @MySchema 
GO

Code om de tabel te maken met een getypte XML-kolom:

CREATE TABLE [dbo].[XmlFiles] (
    [Id] [uniqueidentifier] NOT NULL,

    -- Data from CV element 
    [Data] xml(CONTENT dbo.[MyXmlSchema]) NOT NULL,

CONSTRAINT [PK_XmlFiles] PRIMARY KEY NONCLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Code om Index te maken

CREATE PRIMARY XML INDEX PXML_Data
ON [dbo].[XmlFiles] (Data)

Er zijn wel een paar dingen om rekening mee te houden. De implementatie van Schema door SQL Server ondersteunt xsd:include niet. Dit betekent dat als je een schema hebt dat verwijst naar een ander schema, je deze allemaal naar één schema moet kopiëren en dat moet toevoegen.

Ik zou ook een foutmelding krijgen:

XQuery [dbo.XmlFiles.Data.value()]: Cannot implicitly atomize or apply 'fn:data()' to complex content elements, found type 'xs:anyType' within inferred type 'element({http://www.mynamespace.fake/schemas}:SequenceNumber,xs:anyType) ?'.

als ik probeerde te navigeren boven het knooppunt dat ik had geselecteerd met de knooppuntenfunctie. Bijv.

SELECT
    ,C.value('CVElementId[1]', 'INT') AS [CVElementId]
    ,C.value('../SequenceNumber[1]', 'INT') AS [Level]
FROM 
    [dbo].[XmlFiles]
CROSS APPLY
    [Data].nodes('/CVSet/Level/CVElement') AS T(C)

Vond dat de beste manier om dit aan te pakken was om de OUTER APPLY te gebruiken om in feite een "outer join" op de XML uit te voeren.

SELECT
    ,C.value('CVElementId[1]', 'INT') AS [CVElementId]
    ,B.value('SequenceNumber[1]', 'INT') AS [Level]
FROM 
    [dbo].[XmlFiles]
CROSS APPLY
    [Data].nodes('/CVSet/Level') AS T(B)
OUTER APPLY
    B.nodes ('CVElement') AS S(C)

Ik hoop dat dat iemand helpt, want dat is zo'n beetje mijn dag geweest.



  1. Hoe krijg ik de ID van meerdere ingevoegde rijen in MySQL?

  2. Een Unix-tijdstempel converteren naar een datum/tijd-waarde in PostgreSQL

  3. De landinstelling instellen voor de huidige verbinding in MySQL

  4. Gegroepeerde geaggregeerde pushdown