Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Le meilleur moyen de broyer des données XML dans des colonnes de base de données SQL Server

Je suis tombé sur cette question alors que j'avais un problème très similaire, j'avais exécuté une requête traitant un fichier XML de 7,5 Mo (environ 10 000 nœuds) pendant environ 3,5 à 4 heures avant d'abandonner finalement.

Cependant, après un peu plus de recherche, j'ai découvert qu'après avoir tapé le XML à l'aide d'un schéma et créé un index XML (j'aurais inséré en bloc dans une table), la même requête s'est terminée en ~ 0,04 ms.

Comment est-ce pour une amélioration des performances !

Code pour créer un schéma :

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 pour créer la table avec une colonne XML typée :

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 pour créer l'index

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

Il y a cependant quelques éléments à garder à l'esprit. L'implémentation de Schema par SQL Server ne prend pas en charge xsd:include. Cela signifie que si vous avez un schéma qui fait référence à un autre schéma, vous devrez tous les copier dans un seul schéma et l'ajouter.

J'obtiendrais également une erreur :

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 j'essayais de naviguer au-dessus du nœud que j'avais sélectionné avec la fonction nodes. Par exemple

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)

J'ai découvert que la meilleure façon de gérer cela était d'utiliser OUTER APPLY pour effectuer en fait une "jointure externe" sur le 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)

J'espère que cela aidera quelqu'un, car c'est à peu près ma journée.