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.