2015-12-14 5 views
6

है, मेरे पास तालिका MYTABLE है जिसमें लगभग 25 कॉलम हैं, जिनमें से दो USERID (integer) और USERDATETIME (dateTime) हैं।एसक्यूएल अधिकतम() जहां एक खंड और समूह के साथ एसक्यूएल अधिकतम (

मेरे पास इन दो स्तंभों पर इस तालिका पर एक सूचकांक है, USERID के बाद पहला कॉलम USERDATETIME है।

मैं प्रत्येक USERID के लिए अधिकतम USERDATETIME प्राप्त करना चाहता हूं। तो:

select USERID,MAX(USERDATETIME) 
from MYTABLE WHERE USERDATETIME < '2015-10-11' 
GROUP BY USERID 

मैं अनुकूलक अद्वितीय USERID रों की संख्या के बराबर करना चाहता है में से प्रत्येक अद्वितीय USERID और अधिकतम USERDATETIME संख्या के साथ प्राप्त करने में सक्षम होने की उम्मीद है। और मैं उम्मीद करता हूं कि यह उचित तेज़ हो। मेरे पासटेबल में 2000 उपयोगकर्ता आईडी और 6 मिलियन पंक्तियां हैं I हालांकि, वास्तविक योजना इंडेक्स स्कैन से 6 मिलियन पंक्तियां दिखाती है। यदि मैं USERDATETIME/USERID के साथ एक इंडेक्स का उपयोग करता हूं, तो योजना इंडेक्स की तलाश करने के लिए बदलती है, लेकिन अभी भी 6 मिलियन पंक्तियां हैं।

एसक्यूएल इस तरह से इंडेक्स का उपयोग क्यों नहीं करता है जो संसाधित पंक्तियों की संख्या को कम करेगा?

+0

आप किस डीबीएम का उपयोग कर रहे हैं? –

+0

जहां USERDATETIME <'2015-10-11' कहां है, वहां कितनी पंक्तियां हैं? – Lamak

+0

किस प्रकार की अनुक्रमणिका? –

उत्तर

0

WHERE क्लॉज इंडेक्स का उपयोग करके आपकी क्वेरी पर सीमित कारक है।

एक मानक एसक्यूएल सर्वर क्वेरी के साथ

, अनुक्रमित रिकॉर्ड जल्दी से चयन करने के लिए (जो कि सूचकांक की अनुमति होगी) या तो उपयोग किया जाता है, और रिकॉर्ड को सीमित करने के लिए लौट आए (जो कि सूचकांक की अनुमति नहीं होगा)। तो, यह सूचकांक क्यों तेजी से सीमा की अनुमति नहीं देगा?

जब क्वेरी ऑप्टिमाइज़र WHERE क्लॉज के आधार पर ऑप्टिमाइज़ेशन को मानता है, तो यह एक इंडेक्स की तलाश करता है जो या तो WHERE क्लॉज में आइटम (ओं) से शुरू होता है, या जिसे इस्तेमाल किए गए रिकॉर्ड्स को कुशलतापूर्वक पहचानने के लिए उपयोग किया जा सकता है (या अनुमति नहीं है) परिणाम सेट में होना चाहिए।

इस अनुक्रमणिका के साथ, सर्वर पहले अलग-अलग उपयोगकर्ता आईडी शामिल कर सकता है। फिर यह WHERE क्लॉज के आधार पर मानी गई पंक्तियों को सीमित करना चाहता है। हालांकि, ऐसा करने के लिए, ऑप्टिमाइज़र का अनुमान लगाया जाएगा कि उपयोगकर्ता आईडी को ढूंढने के बाद इसे पूर्ण अनुक्रमणिका या तालिका स्कैन के बराबर करना होगा।

एक वैकल्पिक रणनीति संभव है जो सूचकांक को स्कैन करना, उपयोगकर्ता आईडी और तिथियों को पहचानना है। यही ऑप्टिमाइज़र चुना गया है।

इसका एक संभावित समाधान एक अलग सूचकांक है - एक तिथि, फिर उपयोगकर्ता आईडी - इस्तेमाल किए जाने के अलावा। यह userID maximums की पहचान करने के लिए स्कैन किए जा रहे रिकॉर्ड्स की संख्या को सीमित करेगा, और इस प्रकार थोड़ा तेज़ होगा।

ध्यान दें कि आपकी अनुक्रमणिका तेजी से होगी यदि आपको WHERE क्लॉज की आवश्यकता नहीं है। लेकिन जहां क्लॉज को ऑप्टिमाइज़र को उपयोग के मामले पर विचार करने की आवश्यकता होती है जहां WHERE क्लॉज अंतिम पंक्ति में चुने गए आइटम को सीमित करता है।

इसके अलावा, एक सूचकांक जहां दिनांक फ़ील्ड दे रहा था, आदेश भी अधिक कुशल हो सकता है।

+0

इसके अलावा, आप शामिल कॉलम पर आंकड़े अपडेट करना चाह सकते हैं। यदि औसत पर प्रति उपयोगकर्ता आईडी की 50 तिथियां हैं, तो अनुकूलक प्रति आईडी औसत केवल दो या तीन तिथियों की तुलना में अलग-अलग विकल्प बनायेगा। –

2

यदि आप SQL सर्वर का उपयोग कर रहे हैं तो यह आमतौर पर उत्पाद द्वारा निष्पादित अनुकूलन नहीं है (सीमित मामलों where the table is partitioned by that value को छोड़कर)।

आप मैन्युअल रूप the technique from here

CREATE TABLE YourTable 
    (
    USERID  INT, 
    USERDATETIME DATETIME, 
    OtherColumns CHAR(10) 
) 

CREATE CLUSTERED INDEX IX 
    ON YourTable(USERID ASC, USERDATETIME ASC); 

WITH R 
    AS (SELECT TOP 1 USERID, 
         USERDATETIME 
     FROM YourTable 
     ORDER BY USERID DESC, 
        USERDATETIME DESC 
     UNION ALL 
     SELECT SubQuery.USERID, 
       SubQuery.USERDATETIME 
     FROM (SELECT T.USERID, 
         T.USERDATETIME, 
         rn = ROW_NUMBER() 
           OVER (
           ORDER BY T.USERID DESC, T.USERDATETIME DESC) 
       FROM R 
         JOIN YourTable T 
          ON T.USERID < R.USERID) AS SubQuery 
     WHERE SubQuery.rn = 1) 
SELECT * 
FROM R 

enter image description here

का उपयोग कर आप एक और तालिका UserIds साथ यह संभव है है, तो

साथ और अधिक आसानी से एक कुशल योजना पाने के लिए यह कर सकते हैं हालांकि
SELECT U.USERID, 
     CA.USERDATETIME 
FROM Users U 
     CROSS APPLY (SELECT TOP 1 USERDATETIME 
        FROM YourTable Y 
        WHERE Y.USERID = U.USERID 
        ORDER BY USERDATETIME DESC) CA 

enter image description here

+0

यह एक बहुत ही अच्छी चाल है – Lamak

+0

@ लामाक - पॉल व्हाइट AFAIK –

+0

द्वारा उत्पन्न क्रॉस आवेदन ने बहुत अच्छा काम किया। मुझे इसे एक बाहरी आवेदन में बदलना पड़ा क्योंकि कुछ उपयोगकर्ताओं के पास कोई डेटा नहीं था और हम अभी भी उन्हें हमारी सूची में देखना चाहते थे। एसी या अवरुद्ध होने की तिथि पर इंडेक्स को बदलने से मदद नहीं मिली। जहां खंड (जिसे ज्यादातर मामलों में वैसे भी फ़िल्टर नहीं किया गया है) को हटाकर कोई मदद नहीं मिली। – Mike

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