2010-01-05 18 views
7

से बाहर है, मुझे SQL सर्वर (2005) से एक विचित्र निष्पादन योजना व्यवहार मिलता है।एसक्यूएल सर्वर: पंक्तियों की अनुमानित संख्या

TableName:

SELECT * 
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) as Row, 
       ID, Name 
      FROM Log) AS LogWithRowNumbers 
WHERE Row >= 1 
    AND Row <= 2 

यह: लॉग
... 1000 पंक्तियाँ

  • आईडी पूर्णांक
  • नाम varchar (50)

क्वेरी के आसपास होता है संख्या का अनुमान लगाता है पंक्तियों का बियर 9 के रूप में लौटा (हालांकि यह एक स्पष्ट 2 या कम है)।
इसके अलावा , को हटाने "और पंक्ति < = 2" के बारे में * 5. द्वारा निष्पादन समय में वृद्धि होगी ("और पंक्ति < = 2" और "और पंक्ति < = 9999999999999" एक ही व्यवहार करते हैं)

मैंने अद्यतन आंकड़े लेकिन फिर भी, यह व्यवहार अजीब है। पंक्ति < 99999999999 जोड़ना क्वेरी को तेजी से चलाएगा? क्यूं कर ?

+0

लोग चलो, यह आसानी से reproducable है। जब आपको उनकी आवश्यकता होती है तो उन डीबीए प्रतिभा कहां हैं ?? – Faruz

+0

@ फ़ारज़: मैं डीबीए नहीं हूं। लेकिन क्या क्वेरी तेज होती है जब आपके पास बिना किसी AND/OR (यानी ROW = 1) के एकल मानदंड होते हैं। '> =' और '<=' का उपयोग करने के विरुद्ध 'ROW = 1 या ROW = 2' के दौरान यह कैसा प्रदर्शन करता है। क्या यह आंतरिक रूप से 'लॉग' तालिका के लिए कोई अनुक्रमणिका बनाता है? – shahkalpesh

+0

पंक्ति = 1 या पंक्ति = 2 अनुमानित 58 पंक्तियों को वापस कर दिया ... यह एक आंतरिक सूचकांक नहीं बनाता है लेकिन पीके इंडेक्स (आईडी) का उपयोग करता है। – Faruz

उत्तर

6

मैं SQL सर्वर की आंतरिक कार्यप्रणाली/क्वेरी ऑप्टिमाइज़ेशन प्रक्रिया पर कोई विशेषज्ञ नहीं हूं, लेकिन यहां मेरी 2 पेंस (या यदि आप चाहें तो सेंट) हैं।

मेरा मानना ​​है कि यह WHERE क्लॉज के भीतर ROW_NUMBER() मान के उपयोग के कारण है। उदाहरण के तौर पर, मैंने एक नमूना तालिका बनाई, जो आईडी 1 से 1000 (प्राथमिक कुंजी के रूप में आईडी) से 1000 पंक्तियों के साथ पॉप्युलेट की गई थी।

यदि आप ROW_NUMBER() बाहर ले, और क्वेरी इस तरह आईडी स्तंभ के आधार पर कार्य करें: - के रूप में वास्तव में उम्मीद

Select * FROM 
(
SELECT ID, Name 
FROM Log 
) 
as LogWithRowNumbers 
WHERE ID>=1 and ID<=2 

तो इसे सही ढंग से किया जा रहा है के रूप में 2 पंक्ति संख्या को दर्शाता है।

अब, पीछे की ओर काम कर रहे, भीतर का चयन करने के ROW_NUMBER में जोड़ते हैं, लेकिन छोड़ कहां खंड नीचे की तरह के रूप में है:

Select * FROM 
(
SELECT ROW_NUMBER() OVER (ORDER BY ID DESC) AS RowNo, 
ID, Name 
FROM Log 
) 
as LogWithRowNumbers 
WHERE ID>=1 AND ID <=2 

यह अभी भी रूप में 2.

अंत में सही पंक्ति संख्या से पता चलता , पंक्ति के रूप में ROWNo का उपयोग करने के लिए WHERE क्लॉज को वापस सेट करें क्योंकि आईडी के बजाए कॉलम फ़िल्टर किया जा रहा है, यह तब होता है जब अनुमानित पंक्ति गणना 9 तक बढ़ जाती है।

इसलिए, मेरा मानना ​​है कि यह ROW_NUMBER() फ़ंक्शन का उपयोग है WHERE खंड में फ़िल्टर किया गया है जो सी है ause। तो मुझे लगता है कि ऐसा इसलिए है क्योंकि इस फ़ंक्शन-उत्पादित मूल्य पर वास्तविक तालिका कॉलम पर स्पष्ट रूप से बेहतर/अधिक सटीक आंकड़े उपलब्ध हैं।

मुझे आशा है कि यह कम से कम एक अच्छा प्रारंभिक बिंदु प्रदान करेगा, उम्मीद है कि उपयोगी होगा!

2

AdaTheDev सही है। इस व्यवहार को देखने का कारण यह है क्योंकि एसक्यूएल सर्वर को तालिका के लिए पंक्ति संख्याओं को काम करना होगा इससे पहले कि वह कहां से उपयोग कर सके।

यह चाहिए एक ही परिणाम प्राप्त करने की एक अधिक कुशल तरीका:

SELECT TOP(2) ROW_NUMBER() OVER (ORDER BY ID DESC) as Row, 
ID, Name 
FROM Log 
ORDER BY ID DESC 
+0

मैं जो कह रहा हूं उसे प्राप्त करता हूं, केवल यह एक क्वेरी का उदाहरण है जो मैं करता हूं। मैं आम तौर पर पंक्तियों को पुनः प्राप्त करता हूं 1-10, 10-20 आदि समस्या यह है कि मुझे इसे "पंक्ति <99 99 99" के बिना करना है और इससे अधिक लागत होती है – Faruz

संबंधित मुद्दे