sql >> Base de Datos >  >> RDS >> Sqlserver

La mejor manera de triturar datos XML en columnas de bases de datos de SQL Server

Me topé con esta pregunta mientras tenía un problema muy similar, había estado ejecutando una consulta procesando un archivo XML de 7,5 MB (aproximadamente 10 000 nodos) durante aproximadamente 3,5 a 4 horas antes de finalmente rendirme.

Sin embargo, después de investigar un poco más, descubrí que, después de escribir el XML usando un esquema y crear un índice XML (lo insertaría de forma masiva en una tabla), la misma consulta se completó en ~ 0,04 ms.

¿Qué tal eso para una mejora del rendimiento?

Código para crear un esquema:

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

Código para crear la tabla con una columna XML escrita:

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]

Código para crear Índice

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

Sin embargo, hay algunas cosas a tener en cuenta. La implementación de Schema de SQL Server no es compatible con xsd:include. Esto significa que si tiene un esquema que hace referencia a otro esquema, tendrá que copiarlos todos en un solo esquema y agregarlo.

También obtendría un error:

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

si intentara navegar por encima del nodo que había seleccionado con la función de nodos. Por ejemplo

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)

Encontré que la mejor manera de manejar esto era usar OUTER APPLY para realizar una "unión externa" en el 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)

Espero que eso ayude a alguien, ya que ese ha sido mi día.