Sorum şu: https://stackoverflow.com/q/35575990/5089204
Orada bir cevap vermek için aşağıdaki test senaryosunu yaptım.
Test senaryosu
İlk önce bir test masası oluşturup 100.000 satırla doldururum. Bir rastgele sayı (0 ila 1000) her rastgele sayı için ~ 100 satıra neden olmalıdır. Bu sayı bir varchar col'a ve XML'inize bir değer olarak koyulur.
Daha sonra OP gibi bir çağrı yapıyorum, bunun için .exist () ve .nodes () ile ikinci bir avantajı var, ancak her ikisi de 5 ila 6 saniye sürüyor. Aslında çağrıları iki kez yapıyorum: ikinci kez takaslı sırada ve hafifçe değiştirilmiş arama paraşütleriyle ve önbelleklenmiş sonuçlar veya planlar yoluyla yanlış pozitifleri önlemek için tam yol yerine "// item" ile.
Sonra bir XML dizini oluşturuyorum ve aynı çağrıları yapıyorum
Şimdi - beni gerçekten şaşırtan ne oldu! - .nodes
ile tam yol çok daha yavaş (9 saniye) daha önce ancak .exist()
ile, yarım saniye kadar olan tam yolu da aşağı 0.10 ila yaklaşık sn. (ederken .nodes()
ile kısa yol iyidir, ama yine de çok gerisinde .exist()
)
Sorular:
Kendi testlerim kısaca gündeme geldi: XML dizinleri bir veritabanını aşırı derecede havaya uçurabilir. İşleri aşırı hızlandırabilir (düzenleme 2), ancak sorgularınızı da yavaşlatabilir. Nasıl çalıştıklarını anlamak istiyorum ... Ne zaman bir XML dizini oluşturmalı? Neden .nodes()
bir indeks ile olmadan daha kötü olabilir ? Olumsuz bir etki nasıl önlenebilir?
CREATE TABLE #testTbl(ID INT IDENTITY PRIMARY KEY, SomeData VARCHAR(100),XmlColumn XML);
GO
DECLARE @RndNumber VARCHAR(100)=(SELECT CAST(CAST(RAND()*1000 AS INT) AS VARCHAR(100)));
INSERT INTO #testTbl VALUES('Data_' + @RndNumber,
'<error application="application" host="host" type="exception" message="message" >
<serverVariables>
<item name="name1">
<value string="text" />
</item>
<item name="name2">
<value string="text2" />
</item>
<item name="name3">
<value string="text3" />
</item>
<item name="name4">
<value string="text4" />
</item>
<item name="name5">
<value string="My test ' + @RndNumber + '" />
</item>
<item name="name6">
<value string="text6" />
</item>
<item name="name7">
<value string="text7" />
</item>
</serverVariables>
</error>');
GO 100000
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesFullPath_no_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistFullPath_no_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('//item[@name="name5" and value/@string="My test 500"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistShortPath_no_index;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('//item[@name="name5" and value/@string="My test 500"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesShortPath_no_index;
GO
CREATE PRIMARY XML INDEX PXML_test_XmlColum1 ON #testTbl(XmlColumn);
CREATE XML INDEX IXML_test_XmlColumn2 ON #testTbl(XmlColumn) USING XML INDEX PXML_test_XmlColum1 FOR PATH;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesFullPath_with_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistFullPath_with_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('//item[@name="name5" and value/@string="My test 500"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistShortPath_with_index;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('//item[@name="name5" and value/@string="My test 500"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesShortPath_with_index;
GO
DROP TABLE #testTbl;
EDIT 1 - Sonuçlar
Bu, yerel olarak orta seviye bir dizüstü bilgisayarda kurulu olan SQL Server 2012 ile ortaya çıkan bir sonuçtur. Bu testte, son derece olumsuz olan etkiyi yeniden üretemedim NodesFullPath_with_index
;
NodesFullPath_no_index 6.067
ExistFullPath_no_index 6.223
ExistShortPath_no_index 8.373
NodesShortPath_no_index 6.733
NodesFullPath_with_index 7.247
ExistFullPath_with_index 0.217
ExistShortPath_with_index 0.500
NodesShortPath_with_index 2.410
Daha büyük XML ile EDIT 2 Testi
TT'nin önerisine göre yukarıdaki XML'i kullandım, ancak item
-node'ları yaklaşık 450 maddeye ulaşmak için kopyaladım . XML'de hit-node'un çok yükseğe çıkmasına izin verdim (çünkü bunun .exist()
ilk hitde duracağını düşünüyorum , ancak .nodes()
devam ederdi)
XML dizini oluşturmak, mdf dosyasını ~ 21GB'a düşürdü, ~ 18GB dizine ait görünüyor (!!!)
NodesFullPath_no_index 3min44
ExistFullPath_no_index 3min39
ExistShortPath_no_index 3min49
NodesShortPath_no_index 4min00
NodesFullPath_with_index 8min20
ExistFullPath_with_index 8,5 seconds !!!
ExistShortPath_with_index 1min21
NodesShortPath_with_index 13min41 !!!
.nodes()
ve.exist()
inandırıcı. Ayrıca endeks ilefull path search
daha hızlı olduğu gerçeğini anlamak kolay görünüyor. Bunun anlamı şudur: Bir XML dizini oluşturursanız, herhangi bir genel XPath ( veya veya veya yalnızca düz Xpath ... değil herhangi bir şey) üzerindeki olumsuz etkiden daima haberdar olmalısınız . Aslında sadece tam yolu kullanmalısın - oldukça iyi bir geri çekiliş ...//
*
..
[filter]