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

Il modo migliore per distruggere i dati XML nelle colonne del database di SQL Server

Mi sono imbattuto in questa domanda pur avendo un problema molto simile, stavo eseguendo una query che elaborava un file XML da 7,5 MB (~ circa 10.000 nodi) per circa 3,5 ~ 4 ore prima di arrendermi definitivamente.

Tuttavia, dopo un po' più di ricerca ho scoperto che dopo aver digitato l'XML utilizzando uno schema e creato un Indice XML (inserirei in blocco in una tabella) la stessa query è stata completata in ~ 0,04 ms.

Che ne dici di un miglioramento delle prestazioni!

Codice per creare uno 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

Codice per creare la tabella con una colonna XML tipizzata:

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]

Codice per creare l'Indice

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

Ci sono alcune cose da tenere a mente però. L'implementazione di Schema di SQL Server non supporta xsd:include. Ciò significa che se hai uno schema che fa riferimento ad un altro schema, dovrai copiarli tutti in un unico schema e aggiungerlo.

Inoltre otterrei un errore:

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

se ho provato a navigare sopra il nodo che avevo selezionato con la funzione nodes. Es.

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)

Abbiamo scoperto che il modo migliore per gestirlo era utilizzare OUTER APPLY per eseguire effettivamente un "outer join" sull'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)

Spero che questo aiuti qualcuno dato che è stata praticamente la mia giornata.