2016-12-05 2 views
1

Ich habe eine XML-Datei in einer XML Datentypspalte data in meiner Tabelle records gespeichert.SQL Server-Abfrage XML-Datentyp Leistungsproblem

Die Tabelle sieht wie folgt aus:

create table records 
(
    id int, 
    type nvarchar(28), 
    data xml, 
    posted datetime 
) 

XML-Daten:

<Properties> 
    <data> 
     <Name>novel</Name> 
     <Gender>Female</Gender> 
     <Age>32</Age> 
     <Salary>55k</Salary> 
     <Phone>123-123</Phone> 
    </data> 
</Properties> 

ich zur Zeit folgende Abfrage bin mit Daten aus dieser XML-Spalte zu extrahieren, die mehr als Minuten in 20K Aufzeichnungen nimmt.

select 
    id, 
    posteddate, 
    CONVERT(NVARCHAR(500), data.query('data(Properties/data/Name)')) AS Name, 
    CONVERT(NVARCHAR(500), data.query('data(Properties/data/Gender)')) AS Gender, 
    CONVERT(NVARCHAR(500), data.query('data(Properties/data/Age)')) AS Age, 
    CONVERT(NVARCHAR(500), data.query('data(Properties/data/Salary)')) AS Salary, 
    CONVERT(NVARCHAR(500), data.query('data(Properties/data/Phone)')) AS Phone 
from 
    records 
where 
    type = 'personnel_xml' 

Ich bin sehr neu in XML-Extraktion in SQL Server. Ich glaube, ich befolge den standardoptimierten Ansatz zum Extrahieren von XML-Elementen nicht.

Also, kann jemand helfen, wie kann ich dieses Szenario zu optimieren, wie ich 100 solcher Elemente aus meinem XML als Spalte gespeichert extrahieren muss.

Antwort

2

Angenommen, Sie haben mehrere <data> innerhalb der XML. Hinweis Ich habe eine erweiterte XML-Datei hinzugefügt, die zwei Sätze enthält.

Declare @table table (id int,data xml) 
Insert Into @table values (1,'<Properties><data><Name>novel</Name><Gender>Female</Gender><Age>32</Age><Salary>55k</Salary><Phone>123-123</Phone></data> 
<data><Name>Another Name</Name><Gender>Male</Gender><Age>45</Age><Salary>75k</Salary><Phone>555-1212</Phone></data> 
</Properties>') 

;with cte as (
     Select ID 
      ,RN = Row_Number() over (Partition By ID Order By (Select Null)) 
      ,Data = m.query('.') 
     From @table AS t 
     Cross Apply t.Data.nodes('/Properties/data') AS A(m) 
) 
Select ID 
     ,RN 
     ,Name = Data.value('(data/Name)[1]' ,'nvarchar(500)') 
     ,Gender = Data.value('(data/Gender)[1]','nvarchar(500)') 
     ,Age = Data.value('(data/Age)[1]' ,'nvarchar(500)') 
     ,Salary = Data.value('(data/Salary)[1]','nvarchar(500)') 
     ,Phone = Data.value('(data/Phone)[1]' ,'nvarchar(500)') 
From cte 

Returns

ID RN Name   Gender Age  Salary Phone 
1 1 novel   Female 32  55k  123-123 
1 2 Another Name Male 45  75k  555-1212 
+0

http://stackoverflow.com/users/1570000/john-cappelletti meine xml hat einzelne Datenelement, also in diesem Fall hoffe ich, dass ich Kreuz nicht anwenden muss. Also, aus der Perspektive der Performance, welche sollte man wählen, value() oder query()? – Aarush

+0

@ JohnCappelleti was ist der Unterschied in der Leistung in 'Speichern der gesamten XML in #temp Tabelle und Extrahieren von #temp' ODER 'direkt aus table.column ohne Verwendung von #temp' für mein Szenario von 200s von Elementen ohne zu wiederholen Attribut – Aarush

+0

@LearnByExample Korrekt, da Sie ein einzelnes Datenelement haben, müssen Sie das Kreuz nicht anwenden. und da Sie wissen, der Pfadwert wäre schneller als Abfrage. –

2

Um einen Wert von XML in SQL Server erhalten Sie die value() Method (xml Data Type) verwenden sollten. Und für nicht typisiertes XML sollten Sie den Knoten text() angeben, um eine bessere Leistung zu erzielen.

select R.id, 
     R.posted, 
     R.data.value('(/Properties/data/Name/text())[1]', 'nvarchar(500)') as Name, 
     R.data.value('(/Properties/data/Gender/text())[1]', 'nvarchar(10)') as Gender, 
     R.data.value('(/Properties/data/Age/text())[1]', 'int') as Age, 
     R.data.value('(/Properties/data/Salary/text())[1]', 'nvarchar(10)') as Salary, 
     R.data.value('(/Properties/data/Phone/text())[1]', 'nvarchar(30)') as Phone 
from dbo.records as R 
where type = N'personnel_xml'; 
+1

Hallo, weißt du, wenn die Engine schlau genug ist zu finden, dass '(/ Properties/data /' in allen Fällen gleich ist? Ich dachte es wäre schneller entweder zu benutzen etwas wie John Cappelletti mit '.query()' in einem CTE oder - noch besser - 'CROSS APPLY' auf' .nodes (N '/ Properties/data') 'und dann' .value() 'on' (Name/text()) [1] '. Wird es in diesem Fall nicht immer wieder durch den gesamten 'XPath' navigieren? – Shnugo

+0

@Shnugo Hallo, Ich habe einige Leistungstests in Bezug auf' Cross Apply Nodes' durchgeführt, um ein kürzerer Ausdruck in der values-Funktion, und das ist langsamer (nicht viel). Die Verwendung von 'query()' ist überhaupt nicht gut, da der 'UDX'-Operator, der das neue XML erzeugt, die Dinge verlangsamt. alle * Formen und Formen von XML, aber es tut alles, was ich ausprobiert habe –

+0

@Shnugo BTW, das gesamte XML ist für die Wertfunktion verfügbar, auch wenn Sie 'cross apply nodes' verwenden Was Sie haben, ist etwas, das der "Kontextknoten" genannt wird, der im Grunde genommen eine hierarchische ID ist, die als Parameter für die Wertfunktion verwendet wird. Offensichtlich ist es nicht viel schneller, Knoten zu finden, die dies anstelle eines Pfadausdrucks in der internen Repräsentation des XML verwenden. Zumindest nicht so viel schneller, dass es die Kosten des zusätzlichen Funktionsaufrufs wegen der "Cross Apply Nodes" kompensiert. –