sql >> Databáze >  >> RDS >> Sqlserver

Nejlepší způsob, jak skartovat data XML do databázových sloupců SQL Server

Narazil jsem na tuto otázku, zatímco jsem měl velmi podobný problém, spouštěl jsem dotaz zpracovávající 7,5 MB XML soubor (~přibližně 10 000 uzlů) asi 3,5 až 4 hodiny, než jsem to nakonec vzdal.

Po trochu podrobnějším průzkumu jsem však zjistil, že po zadání XML pomocí schématu a vytvoření indexu XML (vložil bych hromadně do tabulky) byl stejný dotaz dokončen za ~ 0,04 ms.

Jak je to pro zlepšení výkonu!

Kód pro vytvoření schématu:

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

Kód pro vytvoření tabulky se zadaným sloupcem XML:

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]

Kód pro vytvoření indexu

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

Je však třeba mít na paměti několik věcí. Implementace schématu SQL Server nepodporuje xsd:include. To znamená, že pokud máte schéma, které odkazuje na jiné schéma, budete je muset všechny zkopírovat do jediného schématu a přidat to.

Také bych dostal chybu:

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

pokud jsem se pokusil navigovat nad uzel, který jsem vybral pomocí funkce uzlů. Např.

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)

Zjistil jsem, že nejlepší způsob, jak to zvládnout, je použít OUTER APPLY k provedení „vnějšího spojení“ v 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)

Doufám, že to někomu pomůže, protože to byl skoro můj den.



  1. Jak mohu dotazovat hodnotu ve sloupci SQL Server XML

  2. O výhodách tříděných cest

  3. postgresql - sql - počet "skutečných" hodnot

  4. Hloubkový průzkum zabezpečení na úrovni řádků