मेरा प्रश्न इस पर आधारित है: https://stackoverflow.com/q/35575990/5089204
उत्तर देने के लिए मैंने निम्नलिखित परीक्षण-परिदृश्य किया।
परीक्षण परिदृश्य
पहले मैं एक परीक्षण तालिका बनाता हूं और इसे 100.000 पंक्तियों के साथ भरता हूं। एक यादृच्छिक संख्या (0 से 1000) को प्रत्येक यादृच्छिक संख्या के लिए ~ 100 पंक्तियों तक ले जाना चाहिए। यह संख्या एक varchar col में और आपके XML में मान के रूप में डाली जाती है।
फिर मैं ओपी की तरह एक कॉल करता हूं। इसे दूसरे के लिए एक छोटे से लाभ के साथ .exist () और .nodes () के साथ चाहिए, लेकिन दोनों को 5 से 6 सेकंड लगते हैं। वास्तव में मैं दो बार कॉल करता हूं: स्वैप किए गए क्रम में दूसरी बार और कैश्ड परिणामों या योजनाओं के माध्यम से झूठी सकारात्मकता से बचने के लिए पूर्ण पथ के बजाय "// आइटम" के साथ थोड़े बदले हुए खोज पाराम के साथ।
फिर मैं एक XML इंडेक्स बनाता हूं और वही कॉल करता हूं
अब - वास्तव में मुझे क्या आश्चर्य हुआ! - पूर्ण पथ के .nodes
साथ पहले (9 सेकंड) की तुलना में बहुत धीमा है, लेकिन आधे से एक सेकंड तक नीचे है , पूर्ण पथ के साथ भी लगभग 0.10 सेकंड तक नीचे है। (जबकि साथ लघु पथ बेहतर है, लेकिन अभी भी बहुत पीछे ).exist()
.nodes()
.exist()
प्रशन:
मेरे स्वयं के परीक्षण संक्षिप्त रूप में सामने आते हैं: XML इंडेक्स एक डेटाबेस को अत्यधिक उड़ा सकता है। वे चीजों को बहुत तेज कर सकते हैं (2 संपादित करें), लेकिन आपके प्रश्नों को भी धीमा कर सकते हैं। मैं यह समझना चाहता हूं कि वे कैसे काम करते हैं ... किसी को XML इंडेक्स कब बनाना चाहिए? .nodes()
सूचकांक के बिना के साथ बदतर क्यों हो सकता है? नकारात्मक प्रभाव से कैसे बचा जा सकता है?
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 - परिणाम
यह SQL सर्वर 2012 के साथ एक परिणाम है जो स्थानीय रूप से एक मध्यम लैपटॉप पर स्थापित है। इस परीक्षण में मैं उस पर अत्यधिक नकारात्मक प्रभाव को पुन: उत्पन्न नहीं कर सका 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
EDIT 2 बड़े XML के साथ टेस्ट
टीटी के सुझाव के अनुसार मैंने ऊपर XML का उपयोग किया था, लेकिन item
-nodes की प्रतिलिपि लगभग 450 वस्तुओं तक पहुंचने के लिए। मैंने एक्सएमएल में हिट-नोड को बहुत अधिक होने दिया ('क्योंकि मुझे लगता है कि .exist()
पहली हिट पर रुक जाएगा, जबकि .nodes()
जारी रहेगा)
XML-index बनाने ने mdf-file को ~ 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
तेजी से समझने में आसान लगता है। इसका मतलब यह होगा: आप एक एक्सएमएल सूचकांक बनाते हैं, तो आप चाहिए हमेशा किसी भी सामान्य XPath (साथ नकारात्मक प्रभाव के बारे में पता होना//
या*
या..
या[filter]
या कुछ भी न सिर्फ सादा Xpath ...)। वास्तव में आपको केवल पूर्ण पथ का उपयोग करना चाहिए - काफी शानदार बैक ड्रॉ ...