sql >> Database teknologi >  >> RDS >> Sqlserver

Den bedste måde at makulere XML-data i SQL Server-databasekolonner

Faldt over dette spørgsmål, mens jeg havde et meget lignende problem, havde jeg kørt en forespørgsel, der behandlede en 7,5 MB XML-fil (~ca. 10.000 noder) i omkring 3,5~4 timer, før jeg endelig gav op.

Men efter lidt mere research fandt jeg ud af, at efter at have skrevet XML ved hjælp af et skema og oprettet et XML-indeks (jeg ville masseindsætte i en tabel), blev den samme forespørgsel afsluttet på ~ 0,04 ms.

Hvordan er det for en præstationsforbedring!

Kode for at oprette et skema:

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

Kode for at oprette tabellen med en indtastet XML-kolonne:

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]

Kode til at oprette indeks

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

Der er dog et par ting at huske på. SQL Servers implementering af Schema understøtter ikke xsd:include. Det betyder, at hvis du har et skema, der refererer til andre skemaer, skal du kopiere alle disse til et enkelt skema og tilføje det.

Jeg ville også få en fejlmeddelelse:

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

hvis jeg forsøgte at navigere over den node, jeg havde valgt med nodes-funktionen. F.eks.

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)

Fandt ud af, at den bedste måde at håndtere dette på var at bruge OUTER APPLY til faktisk at udføre en "ydre joinforbindelse" 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)

Håber, at det hjælper nogen, da det stort set har været min dag.



  1. Oracle-parametre med IN-sætning?

  2. Hvordan indsætter man flere poster og får identitetsværdien?

  3. Hvad er omkostningerne ved at bruge AUTOINCREMENT til SQLite på Android?

  4. Meddeler postgres ændringer til java-applikationen