sql >> Databasteknik >  >> RDS >> Sqlserver

Det bästa sättet att strimla XML-data till SQL Server-databaskolumner

Snubblade över den här frågan samtidigt som jag hade ett mycket liknande problem, jag hade kört en fråga som bearbetade en 7,5 MB XML-fil (~ungefär 10 000 noder) i cirka 3,5~4 timmar innan jag slutligen gav upp.

Men efter lite mer forskning upptäckte jag att efter att ha skrivit in XML med hjälp av ett schema och skapat ett XML-index (jag skulle infogas i en tabell i bulk) slutfördes samma fråga på ~ 0,04 ms.

Vad är det för en prestandaförbättring!

Kod för att skapa ett schema:

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

Kod för att skapa tabellen med en inskriven XML-kolumn:

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]

Kod för att skapa Index

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

Det finns dock några saker att tänka på. SQL Servers implementering av Schema stöder inte xsd:include. Det betyder att om du har ett schema som refererar till andra scheman, måste du kopiera alla dessa till ett enda schema och lägga till det.

Jag skulle också få ett felmeddelande:

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) ?'.

om jag försökte navigera ovanför noden som jag hade valt med nodfunktionen. T.ex.

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)

Hittade att det bästa sättet att hantera detta var att använda OUTER APPLY för att faktiskt utföra en "outer join" på XML.

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)

Hoppas att det hjälper någon eftersom det i stort sett har varit min dag.



  1. En datamodell för barnkalas

  2. Kopiera data till ny tabell i MySQL

  3. On-Premises vs. SaaS:Databas Monitoring System Architecture

  4. PostgreSQL:Skapa tabell om det inte finns AS