คำถามของฉันเป็นไปตามนี้: https://stackoverflow.com/q/35575990/5089204
เพื่อให้คำตอบนั้นฉันได้ทำการทดสอบสถานการณ์ต่อไปนี้
สถานการณ์การทดสอบ
ก่อนอื่นฉันจะสร้างตารางทดสอบและเติมเต็ม 100.000 แถว ตัวเลขสุ่ม (0 ถึง 1,000) ควรนำไปสู่ ~ 100 แถวสำหรับแต่ละหมายเลขสุ่ม หมายเลขนี้ถูกใส่ในคอลัมน์ varchar และเป็นค่าใน XML ของคุณ
จากนั้นฉันจะโทรเช่น OP มีความต้องการด้วย. exist () และ. nodes () โดยมีข้อได้เปรียบเล็กน้อยสำหรับวินาที แต่ทั้งคู่ใช้เวลา 5 ถึง 6 วินาที ในความเป็นจริงฉันทำการโทรสองครั้ง: ครั้งที่สองในลำดับที่สลับกันและเปลี่ยนการค้นหาเล็กน้อยและใช้ "// item" แทนพา ธ เต็มเพื่อหลีกเลี่ยงผลบวกปลอมผ่านผลลัพธ์หรือแผนแคช
จากนั้นฉันจะสร้างดัชนี XML และทำการโทรเดียวกัน
ตอนนี้ - อะไรทำให้ฉันประหลาดใจจริงๆ! - the .nodes
with full pathนั้นช้ากว่ามาก (9 วินาที) แต่.exist()
ลงไปครึ่งวินาทีโดยที่full pathจะลดลงเหลือประมาณ 0.10 วินาที (ในขณะที่.nodes()
มีเส้นทางที่สั้นจะดีกว่า แต่ยังห่างไกลอยู่เบื้องหลัง.exist()
)
คำถาม:
การทดสอบสั้น ๆ ของฉันเอง: ดัชนี XML สามารถระเบิดฐานข้อมูลได้อย่างมาก พวกเขาสามารถเพิ่มความเร็วในสิ่งต่าง ๆ ได้อย่างมาก (แก้ไข 2) แต่อาจทำให้ข้อความค้นหาของคุณช้าลงเช่นกัน ฉันต้องการที่จะเข้าใจว่ามันทำงานอย่างไร ... เมื่อไหร่ที่ควรจะสร้างดัชนี XML? ทำไมถึง.nodes()
มีดัชนีจะเลวร้ายยิ่งกว่าไม่มี? เราจะหลีกเลี่ยงผลกระทบของ negativ ได้อย่างไร?
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;
แก้ไข 1 - ผลลัพธ์
นี่เป็นผลอย่างหนึ่งกับ SQL Server 2012 ที่ติดตั้งไว้ในเครื่องแล็ปท็อปขนาดกลางในการทดสอบนี้ฉันไม่สามารถสร้างผลกระทบ negativ ได้อย่าง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
แก้ไข 2 ทดสอบด้วย XML ที่ใหญ่กว่า
ตามคำแนะนำของ TT ฉันใช้ XML ด้านบน แต่คัดลอกitem
-node เพื่อเข้าถึงรายการประมาณ 450 รายการ ฉันปล่อยให้ hit-node สูงมากใน XML (เพราะฉันคิดว่า.exist()
มันจะหยุดในการเข้าชมครั้งแรกในขณะที่.nodes()
จะดำเนินการต่อ)
การสร้างดัชนี XML ทำให้ไฟล์ mdf เป็น ~ 21GB ดูเหมือนว่า ~ 18GB จะเป็นของดัชนี (!!!)
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()
และ.exist()
น่าเชื่อถือ นอกจากนี้ความจริงที่ว่าดัชนีด้วยfull path search
เร็วขึ้นนั้นดูเหมือนจะเข้าใจง่าย นี้จะหมายถึง: หากคุณสร้างดัชนี XML คุณต้องเสมอจะตระหนักถึงอิทธิพลเชิงลบกับ XPath ทั่วไปใด ๆ (//
หรือ*
หรือ..
หรือ[filter]
หรืออะไรที่ไม่ธรรมดาเพียง Xpath ... ) ในความเป็นจริงคุณควรใช้เส้นทางแบบเต็มเท่านั้น - ค่อนข้างดีเสมอ ...