2009-04-16 12 views
11

हम लगातार आने वाले डेटा (प्रति सेकंड 5-15 अपडेट) की उचित मात्रा को ट्रैक करने के लिए SQL Server 2005 का उपयोग कर रहे हैं। हमने देखा कि यह कुछ महीनों के लिए उत्पादन में रहा है कि तालिकाओं में से एक ने पूछताछ के लिए एक अश्लील समय लेना शुरू कर दिया है।बड़े डेटासेट पर SQL सर्वर में धीमी विशिष्ट क्वेरी

तालिका 3 स्तंभ होते हैं: - autonumber (क्लस्टर)

  • typeUUID -

    • id GUID उत्पन्न होने से पहले डालने होता है; प्रकार एक साथ
    • typeName समूह के लिए इस्तेमाल किया - प्रकार का नाम (ओह ...)

    प्रश्नों हम चलाते हैं में से एक typeName क्षेत्र पर एक अलग है:

    SELECT DISTINCT [typeName] FROM [types] WITH (nolock); 
    

    typeName क्षेत्र में एक गैर-क्लस्टेड, गैर-अद्वितीय आरोही अनुक्रमणिका है। इस समय तालिका में लगभग 200 एम रिकॉर्ड हैं। जब हम इस सवाल को चलाते हैं, तो प्रश्न वापस लौटने के लिए 5 एम 58 लेता है! शायद हम समझ नहीं रहे हैं कि इंडेक्स कैसे काम करते हैं ... लेकिन मुझे नहीं लगता कि हम उन्हें को गलत समझ चुके हैं जो अधिक है।

    इस थोड़ा और आगे की जांच के लिए हम निम्न क्वेरी भाग गया: के बारे में 10 सेकंड में

    SELECT DISTINCT [typeName] FROM (SELECT TOP 1000000 [typeName] FROM [types] WITH (nolock)) AS [subtbl] 
    

    इस क्वेरी, जैसा कि मैंने उम्मीद होती है, तो वह मेज स्कैनिंग है।

    क्या हम यहां कुछ खो रहे हैं? पहली क्वेरी इतनी लंबी क्यों लेती है?

    संपादित करें: आह, मेरी माफ़ी, पहली क्वेरी 76 रिकॉर्ड लौटाती है, धन्यवाद।

    फ़ॉलो करें: आपके उत्तरों के लिए धन्यवाद, अब मुझे यह समझ में आता है (मुझे नहीं पता कि यह पहले क्यों नहीं था ...)। एक इंडेक्स के बिना, यह 200 एम पंक्तियों में एक टेबल स्कैन कर रहा है, एक इंडेक्स के साथ, यह 200 एम पंक्तियों में एक इंडेक्स स्कैन कर रहा है ...

    एसक्यूएल सर्वर इंडेक्स पसंद करता है, और यह प्रदर्शन को थोड़ा बढ़ावा देता है , लेकिन इसके बारे में उत्साहित होने के लिए कुछ नहीं। इंडेक्स को पुनर्निर्माण करने से क्वेरीम समय 6 एम के बजाय 3 मीटर से अधिक हो गया, एक सुधार, लेकिन पर्याप्त नहीं। मैं बस अपने मालिक को सिफारिश करने जा रहा हूं कि हम टेबल संरचना को सामान्यीकृत करते हैं।

    एक बार फिर, आपकी मदद के लिए सभी को धन्यवाद !!

  • +0

    आप आमतौर पर कितने विशिष्ट प्रकार की अपेक्षा करते हैं? – ninesided

    +0

    ईमानदारी से, ऐसा लगता है जैसे आपका डिज़ाइन मौलिक रूप से त्रुटिपूर्ण है। एक "आने वाली" तालिका में 200 एम रिकॉर्ड? थोड़ी देर के आसपास होने के बाद आप उन्हें कहीं और नहीं फेंक सकते? अपने आवेदन को समझे बिना बेहतर सलाह देना मुश्किल है, लेकिन ऐसा लगता है कि आपको कुछ गंभीर रिफैक्टरिंग की आवश्यकता हो सकती है। – kquinn

    +0

    हां, हमारे पास बहुत सारे डेटा हैं जिनके साथ हम काम कर रहे हैं, वर्तमान में यह 4 महीने का डेटा है। हमें डेटा को विभाजित करने की आवश्यकता होगी, लेकिन हमें अभी तक नहीं मिला है। – Miquella

    उत्तर

    9

    आप इंडेक्स को गलत समझते हैं। यहां तक ​​कि अगर उसने इंडेक्स का उपयोग किया है तो भी यह 200 एम प्रविष्टियों में एक इंडेक्स स्कैन करेगा। इसमें काफी समय लगेगा, साथ ही DISTINCT (एक प्रकार का कारण बनता है) करने में लगने वाला समय और यह चलाने के लिए एक बुरी चीज है। एक प्रश्न में एक DISTINCT को देखते हुए हमेशा एक लाल झंडा उठाता है और मुझे क्वेरी को दोबारा जांचने का कारण बनता है। इस मामले में, शायद आपके पास सामान्यीकरण समस्या है?

    +0

    इसमें कोई संदेह नहीं है, यह आंशिक रूप से डेटा सामान्यीकरण समस्या है, लेकिन पहले से ही डेटा को सामान्य करने से हमें प्रदर्शन समस्याएं आ रही हैं। हम आने वाले डेटा से पहले ही रह रहे हैं। – Miquella

    +0

    यह है एक इंडेक्स स्कैन, लेकिन सूचकांक स्कैन नहीं करना चाहिए (कम से कम इस मामले में) केवल पेड़ के नोड्स को हिट करें, पत्तियों के माध्यम से स्कैन न करें? – Miquella

    +1

    सूचकांक स्कैन समय में वृद्धि, भारी खंडित किया जा सकता है। क्या आप कोई रखरखाव नौकरियां चलाते हैं? आपको उस रात के साथ उस डेटा के साथ ऐसा करना चाहिए। (मान लीजिए कि आप समय निर्धारित कर सकते हैं।) – beach

    0

    दूसरी क्वेरी 1000000 रिकॉर्ड पर काम करती है लेकिन पहले 200 मीटर। मुझे लगता है कि यह एक बड़ा अंतर है :)

    +0

    हां, यह एक बड़ा अंतर होना चाहिए। लेकिन अंतर को उलट दिया जाना चाहिए, क्योंकि पहली क्वेरी इंडेक्स का उपयोग कर रही है, दूसरी क्वेरी टेबल स्कैन कर रही है – Miquella

    1

    मेरा पहला विचार सांख्यिकी है। अंतिम अपडेट ढूंढने के लिए:

    SELECT 
        name AS index_name, 
        STATS_DATE(object_id, index_id) AS statistics_update_date 
    FROM 
        sys.indexes 
    WHERE 
        object_id = OBJECT_ID('MyTable'); 
    

    संपादित करें: आँकड़े अपडेट किया जाता है जब अनुक्रमित पुनर्निर्माण कर रहे हैं, देखते हैं जो मैं नहीं रखा जाता है

    मेरी दूसरी सोचा कि अभी भी वहाँ सूचकांक क्या है? शीर्ष क्वेरी अभी भी एक सूचकांक का उपयोग करना चाहिए। मैंने अभी तक मेरी एक तालिका में 57 मिलियन पंक्तियों के साथ परीक्षण किया है और दोनों इंडेक्स का उपयोग करते हैं।

    +0

    हां, इंडेक्स है, और यह इंडेक्स का उपयोग कर रहा है। :(यह पहली बात थी जिसकी मैंने जांच की थी। यह इंडेक्स स्कैन कर रहा है, लेकिन मुझे नहीं पता कि इंडेक्स के एकमात्र क्षेत्र को स्कैन करने में इतनी देर लगनी चाहिए ... – Miquella

    4

    मुझे संदेह है कि SQL सर्वर भी इंडेक्स का उपयोग करने का प्रयास करेगा, इसे व्यावहारिक रूप से समान मात्रा में काम करना होगा (संकीर्ण तालिका को देखते हुए), सभी 200 एम पंक्तियों को पढ़ना चाहे चाहे वह तालिका या सूचकांक को देखता हो । यदि typeName पर इंडेक्स क्लस्टर किया गया था तो यह समय कम हो सकता है क्योंकि इसे समूहबद्ध करने से पहले सॉर्ट करने की आवश्यकता नहीं है।

    यदि आपके प्रकार की कार्डिनालिटी कम है, तो सारांश तालिका को बनाए रखने के बारे में, जिसमें अलग type मानों की सूची है? मुख्य तालिका के सम्मिलित/अद्यतन पर एक ट्रिगर सारांश तालिका पर एक चेक करेगा और एक नया प्रकार मिलने पर एक नया रिकॉर्ड डालेंगे।

    +0

    +1; डालने पर ट्रिगर जो मैं सोच रहा था उससे बेहतर है (मुख्य के बाद दूसरा INSERT जोड़ें, सारांश तालिका में डालने, और अद्वितीय बाधा उल्लंघन को अनदेखा/अनदेखा करना)। – kquinn

    +0

    मैं वही चीज़ सोच रहा था। सारांश तालिका करें यदि आपको अक्सर अलग क्वेरी चलाने की आवश्यकता है। पंक्तियों को हटाने के बाद आपको तालिका को साफ करने के लिए एक डिलीट ट्रिगर भी जोड़ना होगा। या यदि कोई बड़ा सौदा नहीं है, तो सारांश तालिका को रात में अपडेट करने के लिए SQL कार्य शेड्यूल करें। (हटाए गए प्रकारों को हटा रहा है।) – beach

    +0

    एक विचार अगर DELETEs शामिल हैं: सारांश तालिका में संदर्भ गणना कॉलम है; आईएनएसईआरटी पर ट्रिगर्स इसे बढ़ाता है और इसे कम करने पर इसे कम करता है। यह बहुत अच्छी तरह से काम करना चाहिए। – kquinn

    1

    जैसा कि अन्य ने पहले ही बताया है - जब आप अपनी तालिका में एक चयन डिस्टिंट (टाइपनाम) करते हैं, तो आप एक पूर्ण टेबल स्कैन के साथ समाप्त हो जाएंगे, इससे कोई फर्क नहीं पड़ता।

    तो यह वास्तव में स्कैन किए जाने वाले पंक्तियों की संख्या को सीमित करने का विषय है।

    सवाल यह है कि: आपको अपने DISTINCT टाइपनामों के लिए क्या चाहिए? और आपकी 200 एम पंक्तियों में से कितने अलग हैं? क्या आपके पास केवल कुछ मुट्ठी भर (कुछ सौ से अधिक) विशिष्ट टाइपनाम हैं ??

    यदि ऐसा है - तो आपके पास एक अलग तालिका DISTINCT_TYPENAMES या कुछ हो सकती है और प्रारंभिक रूप से पूर्ण तालिका स्कैन करके उन्हें भरें, और फिर मुख्य पंक्ति में नई पंक्तियां डालने पर, बस यह जांचें कि उनका टाइपनाम पहले से ही DISTINCT_TYPENAMES में है, और यदि नहीं, तो इसे जोड़ें।

    इस तरह, आपके पास अलग-अलग टाइपनाम प्रविष्टियों के साथ एक अलग, छोटी तालिका होगी, जो क्वेरी और/या प्रदर्शित करने के लिए तेज़ी से बिजली होगी।

    मार्क

    +0

    यह एक इंडेक्स स्कैन है, टेबल स्कैन नहीं (मैंने पहले से ही यह सत्यापित किया है)। यह मेरी समझ थी कि यदि सूचकांक सही ढंग से बनाया गया है, तो यह पूरी तालिका के बजाय, सूचकांक को स्कैन करेगा। – Miquella

    +0

    यह तालिका के बजाय इंडेक्स स्कैन कर सकता है और करता है। लेकिन यह समस्या इंडेक्स को हल करने के लिए डिज़ाइन नहीं किया गया है, और इसलिए एक पूर्ण अनुक्रमणिका स्कैन एक पूर्ण तालिका स्कैन की तुलना में इस क्वेरी को काफी तेज़ नहीं कर सकता है। – kquinn

    +0

    इंडेक्स में अभी भी 200 एम प्रविष्टियां होंगी ... –

    0

    मैं कुछ इस तरह की कोशिश करनी चाहिए:

    SELECT typeName FROM [types] WITH (nolock) 
    group by typeName; 
    

    और दूसरी मैं कहूँगा की तरह आप उस स्तंभ को सामान्य बनाने की जरूरत है।

    0

    एक सूचकांक आपको तुरंत एक पंक्ति खोजने में मदद करता है। लेकिन आप डेटाबेस को पूरी तालिका के लिए सभी अद्वितीय प्रकारों को सूचीबद्ध करने के लिए कह रहे हैं। एक सूचकांक उसमें मदद नहीं कर सकता है।

    आप रात की नौकरी चला सकते हैं जो क्वेरी चलाता है और इसे एक अलग तालिका में संग्रहीत करता है। आप अप-टू-डेट डेटा की आवश्यकता होती है, तो आप पिछले आईडी हर रात को स्कैन में शामिल संग्रहीत कर सकती है, और परिणामों को जोड़ सकते:

    select type 
    from nightlyscan 
    union 
    select distinct type 
    from verybigtable 
    where rowid > lastscannedid 
    

    एक अन्य विकल्प दो तालिकाओं में बड़ा तालिका को सामान्य करने के लिए है:

    talbe1: id, guid, typeid 
    type table: typeid, typename 
    

    यदि प्रकारों की संख्या अपेक्षाकृत कम थी तो यह बहुत फायदेमंद होगा।

    3

    DISTINCT कीवर्ड का उपयोग करते समय SQL सर्वर अनुकूलक के साथ एक आईएसई है। समाधान अलग क्वेरी को अलग से अलग करके एक ही क्वेरी योजना को रखने के लिए मजबूर करना था।

    तो हम भी इस तरह के रूप प्रश्नों:

    SELECT DISTINCT [typeName] FROM [types] WITH (nolock); 
    

    और इसे तोड़ने के निम्नलिखित

    SELECT typeName INTO #tempTable1 FROM types WITH (NOLOCK) 
    SELECT DISTINCT typeName FROM #tempTable1 
    

    एक और तरीका में इसके चारों ओर पाने के लिए एक GROUP BY, जो एक अलग अनुकूलन योजना हो जाता है का उपयोग करना है ।

    +1

    यह निष्पादन योजना को बदलने के तरीके के बारे में कुछ और जानकारी जोड़ना अच्छा हो सकता है। – EdC

    1

    एक लूपिंग दृष्टिकोण को कई खोजों का उपयोग करना चाहिए (लेकिन कुछ समांतरता खो देता है)। पंक्तियों की कुल संख्या (कम कार्डिनालिटी) की तुलना में अपेक्षाकृत कुछ विशिष्ट मूल्यों वाले मामलों के लिए प्रयास करना उचित हो सकता है।

    आइडिया इस question से था:

    select typeName into #Result from Types where 1=0; 
    
    declare @t varchar(100) = (select min(typeName) from Types); 
    while @t is not null 
    begin 
        set @t = (select top 1 typeName from Types where typeName > @t order by typeName);  
        if (@t is not null) 
         insert into #Result values (@t); 
    end 
    
    select * from #Result; 
    

    और लग रहा है वहाँ भी कुछ अन्य तरीके (विशेष रूप से पुनरावर्ती CTE @Paul सफेद) कर रहे हैं की तरह:

    different-ways-to-find-distinct-values-faster-methods

    sqlservercentral Topic873124-338-5

    +0

    हां। मैंने सीटीई 'स्किप-स्कैन' के बारे में भी लिखा [यहां] (http://sqlperformance.com/2014/10/t-sql-queries/performance-tuning-whole-plan) –

    0

    मैं कुछ खो सकता था लेकिन अगर यह लोड पर ओवरहेड के साथ एक दृश्य बनाने के लिए अधिक कुशल होगा इसके बजाय अलग-अलग मूल्य और क्वेरी?

    यह चयन के लिए लगभग तत्काल प्रतिक्रिया देगा यदि परिणाम सेट प्रत्येक ओवर पर पॉप्युलेट करने के ऊपर ओवरहेड के साथ काफी छोटा है, हालांकि दृश्य की प्रकृति को देखते हुए कि यह स्वयं में छोटा हो सकता है।

    यह सवाल पूछता है कि आप कितनी बार लिखते हैं जब आप गति के विशिष्ट और महत्व को कितनी बार चाहते हैं।

    0

    एक अनुक्रमित दृश्य इसे तेज़ी से बना सकता है।

    create view alltypes 
    with schemabinding as 
    select typename, count_big(*) as kount 
    from dbo.types 
    group by typename 
    
    create unique clustered index idx 
    on alltypes (typename) 
    

    दृश्य आधार तालिका करने के लिए प्रत्येक परिवर्तन पर तारीख तक रखने के लिए मध्यम होना चाहिए काम (आपके आवेदन पर निर्भर करता है, निश्चित रूप से - मेरी बात यह पूरे तालिका स्कैन करने के लिए नहीं है कि है ।

    select distinct typename 
    into alltypes 
    from types 
    
    alter table alltypes 
    add primary key (typename) 
    
    alter table types add foreign key (typename) references alltypes 
    

    विदेशी कुंजी सुनिश्चित करें कि इस्तेमाल किया सभी मूल्यों माता पिता alltypes तालिका में दिखाई देगा: हर बार या कुछ भी ऐसा पागलपन की हद तक महंगा कर)

    वैकल्पिक रूप से आप एक छोटी सी मेज सभी मूल्यों पकड़े बना सकता है। समस्या यह सुनिश्चित करने में है कि alltypes में types तालिका में उपयोग नहीं किए जाने वाले मान शामिल हैं।

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