Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Najlepszy sposób na niszczenie danych XML w kolumnach bazy danych SQL Server

Natknąłem się na to pytanie, mając bardzo podobny problem, uruchamiałem zapytanie przetwarzające plik XML o wielkości 7,5 MB (około 10 000 węzłów) przez około 3,5 ~ 4 godziny, zanim w końcu się poddałem.

Jednak po nieco dalszych badaniach stwierdziłem, że po wpisaniu XML przy użyciu schematu i utworzeniu indeksu XML (wstawiłbym zbiorczo do tabeli) to samo zapytanie zostało zakończone w ~ 0,04 ms.

Jak to na poprawę wydajności!

Kod do tworzenia schematu:

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

Kod do tworzenia tabeli z wpisaną kolumną 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]

Kod do tworzenia indeksu

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

Należy jednak pamiętać o kilku rzeczach. Implementacja schematu programu SQL Server nie obsługuje xsd:include. Oznacza to, że jeśli masz schemat, który odwołuje się do innego schematu, musisz skopiować je wszystkie do jednego schematu i dodać go.

Dostałbym również błąd:

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

gdybym próbował nawigować nad węzłem, który wybrałem za pomocą funkcji węzłów. Np.

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)

Okazało się, że najlepszym sposobem radzenia sobie z tym jest użycie OUTER APPLY, aby w efekcie wykonać „złączenie zewnętrzne” w pliku 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)

Mam nadzieję, że to komuś pomoże, bo to był mój dzień.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak formatować liczby jako walutę w SQL Server (T-SQL)

  2. Jak działa funkcja SPACE() w SQL Server (T-SQL)

  3. Usuń zduplikowane wiersze w SQL Server

  4. Jak usunąć tagi HTML z ciągu w SQL Server?

  5. Jak generować dane testowe w SQL Server