वाइल्डकार्ड (या शीर्ष) जोड़ने पर SQL सर्वर क्वेरी में बड़ी मंदी


52

मुझे 20 मिलियन जानवरों का एक चिड़ियाघर मिला है जिसे मैं अपने SQL सर्वर 2005 डेटाबेस पर ट्रैक करता हूं। उनमें से लगभग 1% काले हैं और उनमें से लगभग 1% हंस हैं। मैं सभी काले हंसों का विवरण प्राप्त करना चाहता था और इसलिए, मेरे द्वारा किए गए परिणाम पृष्ठ को नहीं बदलना चाहते:

select top 10 * 
from animal 
where colour like 'black'  
and species like 'swan'

(हां, अनजाने में वे क्षेत्र लचर हैं लेकिन वे दोनों अनुक्रमित हैं)। यह पता चलता है कि हमारे पास ऐसे कोई जानवर नहीं हैं क्योंकि क्वेरी लगभग 300 मिलीसेकंड में खाली सेट देती है। अगर मैं 'की तरह' के बजाय '=' का प्रयोग करता तो यह लगभग दो बार उपवास होता, लेकिन मुझे लगता है कि बाद में मुझे कुछ टाइपिंग बचानी है।

यह पता चलता है कि मुखिया ज़ुकीर को लगता है कि उसने कुछ हंसों को 'ब्लैकिश' के रूप में दर्ज किया होगा, इसलिए मैं तदनुसार क्वेरी को संशोधित करता हूं:

select top 10 * 
from animal  
where colour like 'black%' 
and species like 'swan'

पता चला कि उनमें से कोई भी नहीं है (और वास्तव में 'ब्लैक' वाले को छोड़कर कोई 'ब्लैक%' जानवर नहीं हैं), लेकिन खाली लौटने के लिए अब क्वेरी को लगभग 30 सेकंड लगते हैं।

ऐसा लगता है कि यह केवल 'शीर्ष' और '% की तरह' का संयोजन है, हालांकि परेशानी का कारण है

select count(*) 
from animal  
where colour like 'black%' 
and species like 'swan'

0 बहुत जल्दी, और यहां तक ​​कि रिटर्न

select * 
from animal 
where colour like 'black%' 
and species like 'swan'

एक सेकंड के एक हिस्से में खाली लौटता है।

क्या किसी को भी अंदाजा नहीं है कि 'टॉप' और '%' को प्रदर्शन का इतना नाटकीय नुकसान क्यों उठाना चाहिए, खासकर एक खाली परिणाम सेट में?

संपादित करें: बस स्पष्ट करने के लिए, मैं किसी भी FreeText इंडेक्स का उपयोग नहीं कर रहा हूं, मेरा बस यही मतलब है कि फ़ील्ड प्रविष्टि के बिंदु पर फ़्रीटेक्स्ट हैं, अर्थात डेटाबेस में सामान्यीकृत नहीं है। मेरी ओर से भ्रम, खराब शब्दों के लिए खेद है।

जवाबों:


76

यह लागत आधारित आशावादी का निर्णय है।

इस विकल्प में उपयोग की गई अनुमानित लागतें गलत हैं क्योंकि यह विभिन्न स्तंभों में मूल्यों के बीच सांख्यिकीय स्वतंत्रता को मानती है।

यह रो गोल गॉन दुष्ट में वर्णित मुद्दे के समान है जहां सम और विषम संख्या नकारात्मक रूप से सहसंबद्ध हैं।

प्रजनन करना आसान है।

CREATE TABLE dbo.animal(
    id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
    colour varchar(50) NOT NULL,
    species varchar(50) NOT NULL,
    Filler char(10) NULL
);

/*Insert 20 million rows with 1% black and 1% swan but no black swans*/
WITH T
     AS (SELECT TOP 20000000 ROW_NUMBER() OVER (ORDER BY @@SPID) AS RN
         FROM   master..spt_values v1,
                master..spt_values v2,
                master..spt_values v3)
INSERT INTO dbo.animal
            (colour,
             species)
SELECT CASE
         WHEN RN % 100 = 1 THEN 'black'
         ELSE CAST(RN % 100 AS VARCHAR(3))
       END,
       CASE
         WHEN RN % 100 = 2 THEN 'swan'
         ELSE CAST(RN % 100 AS VARCHAR(3))
       END
FROM   T 

/*Create some indexes*/
CREATE NONCLUSTERED INDEX ix_species ON  dbo.animal(species);
CREATE NONCLUSTERED INDEX ix_colour ON  dbo.animal(colour);

अब कोशिश करो

SELECT TOP 10 *
FROM   animal
WHERE  colour LIKE 'black'
       AND species LIKE 'swan' 

यह नीचे दी गई योजना है जिस पर खर्च किया गया है 0.0563167

यहाँ छवि विवरण दर्ज करें

योजना idस्तंभ पर दो अनुक्रमितों के परिणामों के बीच एक मर्ज में शामिल होने में सक्षम है । ( मर्ज के अधिक विवरण यहां एल्गोरिदम में शामिल होते हैं )।

मर्ज ज्वाइन के लिए ज्वाइनिंग की के द्वारा दोनों इनपुट की आवश्यकता होती है।

गैर-अनुक्रमित अनुक्रमणिका द्वारा क्रमबद्ध किए जाते हैं (species, id)और (colour, id)क्रमशः (नॉनिक गैर गुच्छित अनुक्रमित में हमेशा पंक्ति लोकेटर जोड़ा जाता है जो कुंजी के अंत में निहित है यदि स्पष्ट रूप से जोड़ा नहीं गया है)। किसी भी वाइल्डकार्ड के बिना क्वेरी एक समानता की तलाश कर रही है species = 'swan'और colour ='black'। जैसा कि प्रत्येक चाहने वाले प्रमुख स्तंभ से केवल एक सटीक मान प्राप्त कर रहे हैं, idइसलिए मिलान पंक्तियों का आदेश दिया जाएगा इसलिए यह योजना संभव है।

क्वेरी प्लान ऑपरेटर्स बाएं से दाएं निष्पादित करते हैं । बाएं ऑपरेटर से अपने बच्चों से पंक्तियों का अनुरोध किया जाता है, जो बदले में अपने बच्चों से पंक्तियों का अनुरोध करते हैं (और जब तक पत्ती के नोड्स तक नहीं पहुंच जाते हैं)। TOPइटरेटर एक बार 10 प्राप्त किया गया है अपने बच्चे से अधिक पंक्तियां का अनुरोध बंद हो जाएगा।

एसक्यूएल सर्वर में सूचकांक पर आंकड़े हैं जो यह बताते हैं कि 1% पंक्तियाँ प्रत्येक विधेय से मेल खाती हैं। यह मानता है कि ये आँकड़े स्वतंत्र हैं (यानी या तो सकारात्मक या नकारात्मक रूप से सहसंबद्ध नहीं हैं) ताकि औसतन एक बार 1,000 पंक्तियों को संसाधित करने के बाद यह पहली विधेयकता से मेल खाता हो, यह 10 मिलान दूसरा मिल जाएगा और बाहर निकल सकता है। (वास्तव में ऊपर की योजना 1,000 के बजाय 987 दिखाती है लेकिन पर्याप्त रूप से बंद है)।

वास्तव में, जैसा कि विधेयकों को नकारात्मक रूप से सहसंबद्ध किया जाता है वास्तविक योजना यह दर्शाती है कि प्रत्येक अनुक्रमणिका से संसाधित होने के लिए आवश्यक सभी 200,000 मिलान पंक्तियों को शामिल किया गया है लेकिन इसे कुछ हद तक कम किया गया है क्योंकि शून्य शामिल पंक्तियों का अर्थ है कि शून्य लुकअप वास्तव में आवश्यक थे।

तुलना करना

SELECT TOP 10 *
FROM   animal
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan' 

जो नीचे दी गई योजना को पूरा करता है 0.567943

यहाँ छवि विवरण दर्ज करें

अनुगामी वाइल्डकार्ड के जुड़ने से अब एक इंडेक्स स्कैन हुआ है। 20 मिलियन रो टेबल पर स्कैन के लिए योजना की लागत अभी भी काफी कम है।

querytraceon 9130कुछ और जानकारी जोड़ना

SELECT TOP 10 *
FROM   animal
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan'       
OPTION (QUERYTRACEON 9130)  

यहाँ छवि विवरण दर्ज करें

यह देखा जा सकता है कि एसक्यूएल सर्वर यह अनुमान लगाता है कि उसे केवल १००,००० पंक्तियों को स्कैन करने की आवश्यकता होगी, क्योंकि यह १० विधेय से मेल खाता है और TOPपंक्तियों का अनुरोध करना बंद कर सकता है।

फिर से यह स्वतंत्रता की धारणा के साथ समझ में आता है 10 * 100 * 100 = 100,000

अंत में कोशिश करते हैं और एक इंडेक्स चौराहे की योजना को मजबूर करते हैं

SELECT TOP 10 *
FROM   animal WITH (INDEX(ix_species), INDEX(ix_colour))
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan' 

यह मेरे लिए 3.4625 की अनुमानित लागत के साथ एक समानांतर योजना देता है

यहाँ छवि विवरण दर्ज करें

यहां मुख्य अंतर यह है कि colour like 'black%'विधेय अब कई अलग-अलग रंगों से मेल खा सकता है। इसका मतलब यह है कि उस विधेय के लिए मिलान सूचकांक पंक्तियों को अब क्रम में क्रमबद्ध किए जाने की गारंटी नहीं है id

उदाहरण के लिए, सूचकांक चाहने like 'black%'वाले निम्नलिखित पंक्तियों को वापस कर सकते हैं

+------------+----+
|   Colour   | id |
+------------+----+
| black      | 12 |
| black      | 20 |
| black      | 23 |
| black      | 25 |
| blackberry |  1 |
| blackberry | 50 |
+------------+----+

प्रत्येक रंग के भीतर आईडी का आदेश दिया जाता है, लेकिन विभिन्न रंगों में आईडी अच्छी तरह से नहीं हो सकती हैं।

परिणामस्वरूप SQL सर्वर अब मर्ज ज्वाइन इंडेक्स चौराहे (बिना ब्लॉकिंग सॉर्ट ऑपरेटर को जोड़े) नहीं कर सकता है और इसके बजाय हैश ज्वाइन करने का विकल्प रखता है। हैश जॉइन बिल्ड इनपुट पर रोक लगा रहा है, इसलिए अब लागत इस तथ्य को दर्शाती है कि सभी मिलान पंक्तियों को बिल्ड इनपुट से संसाधित करने की आवश्यकता होगी, यह मानने के बजाय कि इसे पहली योजना के रूप में केवल 1,000 स्कैन करना होगा।

जांच इनपुट गैर अवरुद्ध है, लेकिन यह अभी भी गलत अनुमान लगाता है कि यह 987 पंक्तियों को संसाधित करने के बाद जांच को रोकने में सक्षम होगा।

(गैर-अवरोधक बनाम अवरुद्ध पुनरावृत्तियों पर आगे की जानकारी यहाँ)

अतिरिक्त अनुमानित पंक्तियों की बढ़ी हुई लागत को देखते हुए और हैश आंशिक रूप से क्लस्टर किए गए इंडेक्स स्कैन में शामिल होता है जो सस्ता दिखता है।

बेशक अभ्यास में "आंशिक" क्लस्टर इंडेक्स स्कैन आंशिक नहीं है और इसे योजनाओं की तुलना करते समय मान लिए गए 100 हजार के बजाय पूरे 20 मिलियन पंक्तियों के माध्यम से चुगना आवश्यक है।

के मूल्य में वृद्धि TOP(या इसे पूरी तरह से हटा देना) अंततः एक टिपिंग बिंदु का सामना करता है जहां पंक्तियों की संख्या का अनुमान है कि सीआई स्कैन को कवर करने की आवश्यकता होगी, जिससे योजना अधिक महंगी दिखती है और यह सूचकांक चौराहे की योजना को प्रभावित करता है। मेरे लिए दो योजनाओं के बीच का कट ऑफ बिंदु TOP (89)बनाम है TOP (90)

आपके लिए यह अच्छी तरह से भिन्न हो सकता है क्योंकि यह निर्भर करता है कि क्लस्टर इंडेक्स कितना चौड़ा है।

TOPसीआई स्कैन को हटाने और मजबूर करना

SELECT *
FROM   animal WITH (INDEX = 1)
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan' 

88.0586मेरे उदाहरण तालिका के लिए मेरी मशीन पर खर्च किया गया है।

यदि SQL सर्वर को पता था कि चिड़ियाघर में कोई काला हंस नहीं है और इसे केवल 100,000 पंक्तियों को पढ़ने की बजाय एक पूर्ण स्कैन करने की आवश्यकता है, तो यह योजना नहीं चुनी जाएगी।

मैंने मल्टी कॉलम आँकड़े चालू करने animal(species,colour)और animal(colour,species)फ़िल्टर करने की कोशिश की है, animal (colour) where species = 'swan'लेकिन इनमें से कोई भी यह समझाने में मदद नहीं करता है कि काले हंस मौजूद नहीं हैं और TOP 10स्कैन को 100,000 से अधिक पंक्तियों को संसाधित करने की आवश्यकता होगी।

यह "समावेश धारणा" के कारण है जहां SQL सर्वर अनिवार्य रूप से मानता है कि यदि आप किसी ऐसी चीज की खोज कर रहे हैं जो संभवतः मौजूद है।

2008+ पर, पंक्तिबद्ध लक्ष्यों को बंद करने वाला एक प्रलेखित ट्रेस ध्वज 4138 है। इसका प्रभाव यह है कि योजना को इस धारणा के बिना लागत की जाती है कि TOPबच्चे संचालकों को सभी मिलान पंक्तियों को पढ़े बिना जल्दी समाप्त करने की अनुमति देगा। इस ट्रेस ध्वज के साथ मैं स्वाभाविक रूप से अधिक इष्टतम सूचकांक प्रतिच्छेदन योजना प्राप्त करता हूं।

SELECT TOP 10 *
FROM   animal
WHERE  colour LIKE 'black%'
       AND species LIKE 'swan'
OPTION (QUERYTRACEON 4138)       

यहाँ छवि विवरण दर्ज करें

यह योजना अब दोनों इंडेक्स लाइक्स में पूरी 200 हजार पंक्तियों को पढ़ने के लिए सही तरीके से खर्च होती है, लेकिन लागतों में महत्वपूर्ण लुकअप (अनुमानित 2 हजार बनाम वास्तविक 0. यह TOP 10अधिकतम 10 तक सीमित होगा लेकिन ट्रेस ध्वज इसे ध्यान में रखता है) । फिर भी योजना का चयन सीआई द्वारा पूर्ण सीआई स्कैन की तुलना में काफी सस्ता है।

बेशक यह योजना संयोजन जिसके लिए इष्टतम नहीं हो सकता है कर रहे हैं आम। जैसे कि सफेद हंस।

एक animal (colour, species)आदर्श सूचकांक या आदर्श रूप animal (species, colour)से क्वेरी दोनों परिदृश्यों के लिए अधिक कुशल होगी।

समग्र सूचकांक का सबसे कुशल उपयोग LIKE 'swan'करने के लिए भी बदलना होगा = 'swan'

नीचे दी गई सारणी सभी चार क्रमपरिवर्तन के लिए निष्पादन योजनाओं में दिखाए गए विधेय और अवशिष्ट विधेयकों को दर्शाती है।

+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+
|                 WHERE clause                 |       Index       |                         Seek Predicate                         |              Residual Predicate              |
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+
| colour LIKE 'black%' AND species LIKE 'swan' | ix_colour_species | colour >= 'black' AND colour < 'blacL'                         | colour like 'black%' AND species like 'swan' |
| colour LIKE 'black%' AND species LIKE 'swan' | ix_species_colour | species >= 'swan' AND species <= 'swan'                        | colour like 'black%' AND species like 'swan' |
| colour LIKE 'black%' AND species = 'swan'    | ix_colour_species | (colour,species) >= ('black', 'swan')) AND colour < 'blacL'    | colour LIKE 'black%' AND species = 'swan'    |
| colour LIKE 'black%' AND species = 'swan'    | ix_species_colour | species = 'swan' AND (colour >= 'black' and colour <  'blacL') | colour like 'black%'                         |
+----------------------------------------------+-------------------+----------------------------------------------------------------+----------------------------------------------+

15

इस पेचीदा को संस्थापक, मैंने कुछ खोज की और इस क्यू / ए पर ठोकर खाई (कैसे और क्यों) TOP एक निष्पादन योजना को प्रभावित करता है?

मूल रूप से, TOP का उपयोग करने से इसके बाद के ऑपरेटरों की लागत में बदलाव होता है (एक नॉनवेज तरीके से), जिसके कारण ओवरल प्लान में भी बदलाव होता है (यह बहुत अच्छा होगा यदि आपने TOP 10 के साथ और बिना ExecPlans को शामिल किया है), जो बहुत अधिक बदलाव के निष्पादन को बदल देता है। पूछताछ।

उम्मीद है की यह मदद करेगा।

उदाहरण के लिए, मैंने इसे डेटाबेस पर आज़माया है और जब-जब कोई शीर्ष लागू नहीं होता, समानता का उपयोग किया जाता है-शीर्ष के साथ, समानता का उपयोग नहीं किया जाता है

इसलिए, फिर से, अपनी निष्पादन योजनाओं को दिखाने से अधिक जानकारी मिलेगी।

आपका दिन शुभ हो


-1

मेरा मानना ​​है कि यह MSSQL 2005 की अंतर्निहित प्रकृति के कारण हो सकता है और क्वेरी ऑप्टिमाइज़र जिस तरह से निर्णय लेता है कि निष्पादन योजना सबसे कुशल है।

यदि आप SQL चर का उपयोग करते हैं, तो इसे नेस्टेड लूप के बजाय हैश मैचों का उपयोग करके क्वेरी ऑप्टिमाइज़र को 'ट्रिक' करना चाहिए, जिसके परिणामस्वरूप समानता का एक उच्च स्तर होगा।

प्रयत्न, कोशिश:

DECLARE @topn INT = 10
SELECT TOP (@topn) *
FROM    animal
WHERE   colour LIKE 'black%' 
AND species LIKE 'swan'

5
मुश्किल होता TOPएक चर में मूल्य का मतलब है कि यह मान लेंगे TOP 100बजाय TOP 10। यह दोनों योजनाओं के बीच की टिपिंग बिंदु के आधार पर मदद कर सकता है या नहीं भी कर सकता है।
मार्टिन स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.