अनुकूलन बड़ी तालिका में शामिल हो


10

मैं एक क्वेरी के बाहर कुछ और प्रदर्शन को सहने की कोशिश कर रहा हूं जो ~ 250 मिलियन रिकॉर्ड के साथ एक तालिका तक पहुंच रहा है। वास्तविक (अनुमानित नहीं) निष्पादन योजना के मेरे पढ़ने से, पहली अड़चन एक क्वेरी है जो इस तरह दिखती है:

select
    b.stuff,
    a.added,
    a.value
from
    dbo.hugetable a
    inner join
    #smalltable b on a.fk = b.pk
where
    a.added between @start and @end;

नीचे दी गई सारणी और अनुक्रमित की परिभाषाओं के लिए नीचे देखें।

निष्पादन योजना यह दर्शाती है कि #smalltable पर नेस्टेड लूप का उपयोग किया जा रहा है, और hugetable पर इंडेक्स स्कैन को 480 बार (#smalltable में प्रत्येक पंक्ति के लिए) निष्पादित किया जा रहा है। यह मुझे पीछे की ओर लगता है, इसलिए मैंने इसके बजाय एक मर्ज जॉइन को मजबूर करने की कोशिश की है:

select
    b.stuff,
    a.added,
    a.value
from
    dbo.hugetable a with(index = ix_hugetable)
    inner merge join
    #smalltable b with(index(1)) on a.fk = b.pk
where
    a.added between @start and @end;

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

जब मैं ऐसा करता हूं, हालांकि, क्वेरी 2 1/2 मिनट से अधिक 9 तक चलती है। मुझे उम्मीद होगी कि संकेत एक अधिक कुशल जुड़ाव को बाध्य करेंगे जो केवल प्रत्येक तालिका पर एक ही पास करता है, लेकिन स्पष्ट रूप से नहीं।

किसी भी मार्गदर्शन का स्वागत है। यदि आवश्यक हो तो अतिरिक्त जानकारी।

अपडेट (2011/06/02)

तालिका में अनुक्रमण को पुनर्गठित करने के बाद, मैंने महत्वपूर्ण प्रदर्शन अंतर्द्वंद बनाए हैं, हालांकि जब मैंने बड़ी तालिका में डेटा को सारांशित करने की बात आती है, तो मुझे एक नई बाधा दी है। परिणाम महीने से एक सारांश है, जो वर्तमान में निम्नलिखित की तरह दिखता है:

select
    b.stuff,
    datediff(month, 0, a.added),
    count(a.value),
    sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
    dbo.hugetable a
    inner join
    #smalltable b on a.fk = b.pk
group by
    b.stuff,
    datediff(month, 0, a.added);

वर्तमान में, hugetable में एक क्लस्टर इंडेक्स pk_hugetable (added, fk)(प्राथमिक कुंजी) है, और एक गैर-क्लस्टर इंडेक्स है जो दूसरे रास्ते पर जा रहा है ix_hugetable (fk, added)

उपरोक्त 4 कॉलम के बिना, ऑप्टिमाइज़र पहले से ही नेस्टेड लूप जॉइन करता है, बाहरी इनपुट के रूप में #smalltable का उपयोग करते हुए, और एक गैर-क्लस्टर इंडेक्स लूप को आंतरिक लूप (480 बार फिर से निष्पादित करना) के रूप में उपयोग करता है। मुझे चिंता क्या अनुमानित पंक्तियों (12,958.4) और वास्तविक पंक्तियों (74,668,468) के बीच असमानता है। इन आरी की सापेक्ष लागत 45% है। हालांकि रनिंग टाइम एक मिनट से कम है।

4 वें कॉलम के साथ, रनिंग टाइम 4 मिनट तक बढ़ जाता है। यह समान सापेक्ष लागत (45%) के लिए इस बार (2 निष्पादन) क्लस्टर्ड इंडेक्स पर तलाश करता है, हैश मैच (30%) के माध्यम से एकत्र करता है, फिर #smalltable (0%) पर एक हैश जुड़ता है।

मैं अपनी अगली कार्रवाई के लिए अनिश्चित हूं। मेरी चिंता यह है कि न तो तिथि सीमा की खोज होती है और न ही सम्मिलित विधेयकों की गारंटी दी जाती है या यहां तक ​​कि उन सभी के परिणाम में भारी गिरावट की संभावना है। अधिकांश मामलों में दिनांक सीमा केवल रिकॉर्ड के 10-15% के बराबर हो जाएगी , और fk पर आंतरिक जुड़ाव शायद 20-30% को फ़िल्टर कर सकता है।


जैसा कि विल ए द्वारा अनुरोध किया गया है, के परिणाम sp_spaceused:

name      | rows      | reserved    | data        | index_size  | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB

#smalltable के रूप में परिभाषित किया गया है:

create table #endpoints (
    pk uniqueidentifier primary key clustered,
    stuff varchar(6) null
);

जबकि dbo.hugetable को इस प्रकार परिभाषित किया गया है:

create table dbo.hugetable (
    id uniqueidentifier not null,
    fk uniqueidentifier not null,
    added datetime not null,
    value decimal(13, 3) not null,

    constraint pk_hugetable primary key clustered (
        fk asc,
        added asc,
        id asc
    )
    with (
        pad_index = off, statistics_norecompute = off,
        ignore_dup_key = off, allow_row_locks = on,
        allow_page_locks = on
    )
    on [primary]
)
on [primary];

निम्नलिखित सूचकांक परिभाषित के साथ:

create nonclustered index ix_hugetable on dbo.hugetable (
    fk asc, added asc, id asc
) include(value) with (
    pad_index = off, statistics_norecompute = off,
    sort_in_tempdb = off, ignore_dup_key = off,
    drop_existing = off, online = off,
    allow_row_locks = on, allow_page_locks = on
)
on [primary];

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


क्या आप sp_spaceused 'dbo.hugetable' का परिणाम शामिल कर सकते हैं, कृपया?
एक

किया, तालिका परिभाषाओं की शुरुआत के ठीक ऊपर जोड़ा गया।
क्विक जो स्मिथ

यह निश्चित है। इसका हास्यास्पद आकार वह कारण है जो मैं इसमें देख रहा हूं।
क्विक जो स्मिथ

जवाबों:


5

आपका ix_hugetableलुक काफी बेकार है क्योंकि:

  • यह है संकुल अनुक्रमणिका (पी)
  • INCLUDE से कोई फर्क नहीं पड़ता क्योंकि एक संकुल सूचकांक सभी गैर-कुंजी स्तंभों को सम्मिलित करता है (निम्नतम पत्ती पर महत्वपूर्ण मान = INCLUDEd = एक संकुल सूचकांक क्या है)

इसके अतिरिक्त: - जोड़ा या fk पहले होना चाहिए - ID पहले है = ज्यादा उपयोग नहीं

गुच्छेदार कुंजी को बदलने (added, fk, id)और छोड़ने की कोशिश करें ix_hugetable। आप पहले से ही कोशिश कर चुके हैं (fk, added, id)। यदि और कुछ नहीं है, तो आप बहुत सारे डिस्क स्थान और इंडेक्स रखरखाव को बचाएंगे

एक अन्य विकल्प तालिका आदेश बोह तरीके और कोई JOIN / INDEX संकेत के साथ FORCE ORDER संकेत की कोशिश करना हो सकता है। मैं व्यक्तिगत रूप से JOIN / INDEX संकेत का उपयोग नहीं करने का प्रयास करता हूं क्योंकि आप ऑप्टिमाइज़र के विकल्प हटा देते हैं। कई साल पहले मुझे बताया गया था (एक एसक्यूएल गुरु के साथ संगोष्ठी) है कि जब आपके पास बड़ी मेज पर छोटी सी मेज: YMMV 7 साल बाद है, तो FORD ORDER संकेत मदद कर सकता है ...

ओह, और हमें बताएं कि DBA कहां रहता है इसलिए हम कुछ टक्कर समायोजन की व्यवस्था कर सकते हैं

संपादित करें, 02 जून अद्यतन के बाद

4 वां कॉलम गैर-क्लस्टर किए गए इंडेक्स का हिस्सा नहीं है इसलिए यह क्लस्टर किए गए इंडेक्स का उपयोग करता है।

NC स्तंभ को INCLUDE मान स्तंभ में बदलने का प्रयास करें, ताकि इसे संकुल अनुक्रमणिका के लिए मान स्तंभ तक नहीं पहुँचना पड़े

create nonclustered index ix_hugetable on dbo.hugetable (
    fk asc, added asc
) include(value)

नोट: यदि मूल्य अशक्त नहीं है, तो यह COUNT(*)शब्दार्थ के समान है । लेकिन SUM के लिए इसे वास्तविक मूल्य की आवश्यकता है , अस्तित्व की नहीं ।

उदाहरण के लिए, अगर आप को बदलने COUNT(value)के लिए COUNT(DISTINCT value) बिना सूचकांक बदल रहा है यह क्वेरी फिर से, क्योंकि यह एक मूल्य के रूप में मूल्य की प्रक्रिया है, नहीं अस्तित्व के रूप में तोड़ना चाहिए।

क्वेरी को 3 कॉलम की आवश्यकता है: जोड़ा, fk, मान। पहले 2 फ़िल्टर्ड / ज्वाइन हैं इसलिए प्रमुख कॉलम हैं। मूल्य का उपयोग सिर्फ इतना है कि शामिल किया जा सकता है। एक कवरिंग इंडेक्स का क्लासिक उपयोग।


हह, मेरे पास यह मेरे सिर में था कि क्लस्टर और गैर-क्लस्टर किए गए अनुक्रमितों ने अलग-अलग क्रम में fk & जोड़ा था। मुझे विश्वास नहीं हो रहा है कि मैंने इस पर ध्यान नहीं दिया, लगभग उतना ही जितना मैं विश्वास नहीं कर सकता कि यह पहली जगह में इस तरह से सेटअप था। मैं कल क्लस्टर इंडेक्स को बदल दूंगा, फिर कॉफ़ी के लिए सड़क पर जाऊंगा जब यह फिर से बनेगा।
क्विक जो स्मिथ

मैंने अनुक्रमण को बदल दिया है और बड़ी मेज पर चाहने वालों की संख्या को कम करने के प्रयास में फोर्स ओआरडीईआर के साथ टकरा गया था लेकिन कोई फायदा नहीं हुआ। मेरा प्रश्न अपडेट कर दिया गया है।
क्विक जो स्मिथ

@ क्विक जो स्मिथ: मेरे जवाब को अपडेट किया
gbn

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

2

hugetableकेवल addedकॉलम पर एक इंडेक्स को परिभाषित करें ।

DB के कॉलम सूची के केवल दाईं ओर एक बहु-भाग (मल्टी कॉलम) इंडेक्स का उपयोग करेगा क्योंकि इसमें बाईं ओर से गणना के मान हैं। आपकी क्वेरी fkपहली क्वेरी के क्लॉज़ में निर्दिष्ट नहीं है , इसलिए यह इंडेक्स को अनदेखा करता है।


निष्पादन योजना से पता चलता है कि सूचकांक (ix_hugetable) की तलाश की जा रही है। या आप कह रहे हैं कि यह सूचकांक क्वेरी के लिए उपयुक्त नहीं है?
क्विक जो स्मिथ

सूचकांक उचित नहीं है। कौन जानता है कि यह "सूचकांक का उपयोग" कैसे है। अनुभव बताता है कि यह आपकी समस्या है। इसे आज़माएं और हमें बताएं कि यह कैसे जाता है।
बोहेमियन

@ क्विक जो स्मिथ - क्या आपने @ बोहेमियन के सुझाव की कोशिश की? परिणाम कहां हैं?
लेवेन कीर्सेमेकर्स

2
मैं असहमत हूं: ऑन क्लॉज को तार्किक रूप से पहले संसाधित किया गया है और प्रभावी रूप से WHERE व्यवहार में है इसलिए ओपी को पहले दोनों कॉलमों को आजमाना है। JOIN के लिए fk मान प्राप्त करने के लिए fk पर कोई अनुक्रमणिका = संकुल अनुक्रमणिका स्कैन या कुंजी लुकअप नहीं। क्या आप अपने द्वारा बताए गए व्यवहार के लिए कुछ संदर्भ जोड़ सकते हैं? विशेष रूप से SQL सर्वर के लिए आपको इस RDBMS के लिए उत्तर देने का बहुत कम इतिहास है। दरअसल, -1 में पूर्वव्यापी के रूप में यह टिप्पणी टाइप करें
gbn

2

निष्पादन योजना यह दर्शाती है कि #smalltable पर नेस्टेड लूप का उपयोग किया जा रहा है, और hugetable पर इंडेक्स स्कैन को 480 बार (#smalltable में प्रत्येक पंक्ति के लिए) निष्पादित किया जा रहा है।

यह आदेश है कि मैं क्वेरी ऑप्टिमाइज़र का उपयोग करने की उम्मीद करूंगा, यह मानते हुए कि एक लूप सही विकल्प में शामिल होता है। इसका विकल्प है कि आप 250M बार लूप लें और हर बार #temp टेबल में एक लुकअप करें - जिसमें घंटे / दिन लग सकते हैं।

जिस सूचकांक को आप MERGE जॉइन में उपयोग करने के लिए मजबूर कर रहे हैं, वह बहुत ज्यादा 250M पंक्तियाँ * 'प्रत्येक पंक्ति का आकार' है - छोटा नहीं, कम से कम GB का एक जोड़ा। sp_spaceusedआउटपुट को 'एक दो जीबी' के रूप में देखते हुए, यह काफी हद तक एक ख़ामोशी हो सकती है - MERGE जॉइन के लिए आवश्यक है कि आप इंडेक्स के माध्यम से ट्रॉल करें जो बहुत I / O गहन होने वाला है।


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

2
लेकिन इसके अलावा भी बहुत कुछ है। यदि #smalltable में बड़ी संख्या में पंक्तियाँ होती हैं तो मर्ज जॉइन उपयुक्त हो सकता है। यदि, जैसा कि यह नाम से पता चलता है, इसमें छोटी संख्या में पंक्तियाँ होती हैं तो एक लूप जॉइन सही विकल्प हो सकता है। कल्पना करें कि #smalltable में एक या दो पंक्तियाँ थीं, और दूसरी तालिका से कुछ मुट्ठी भर पंक्तियों के साथ मेल खाता था - यहाँ एक मर्ज को सही ठहराना कठिन होगा।
एक

मुझे लगा कि वहाँ यह अधिक था; मुझे अभी पता नहीं था कि क्या हो सकता है। डेटाबेस अनुकूलन बिल्कुल मेरा मजबूत सूट नहीं है, जैसा कि आप शायद पहले ही अनुमान लगा चुके हैं।
क्विक जो स्मिथ

@ क्विक जो स्मिथ - sp_spaceused के लिए धन्यवाद। 75GB सूचकांक और 18GB डेटा - क्या ix_hugetable टेबल पर एकमात्र सूचकांक नहीं है?
एक

1
+1 करेंगे। वर्तमान में योजनाकार सही काम कर रहा है। जिस तरह से आपकी तालिकाओं को क्लस्टर किया जाता है, उसके कारण यह समस्या यादृच्छिक डिस्क में है।
डेनिस डी बर्नार्डी

1

आपका सूचकांक गलत है। अनुक्रमित डॉस और डॉन्स देखें ।

जैसे ही चीजें खड़ी होती हैं, आपकी एकमात्र उपयोगी इंडेक्स छोटी मेज की प्राथमिक कुंजी पर होती है। एकमात्र उचित योजना इस प्रकार है कि छोटी मेज को स्कैन करना और विशाल के साथ गड़बड़ी को रोकना।

पर एक संकुल सूचकांक जोड़ने का प्रयास करें hugetable(added, fk)। इससे प्लानर को विशाल टेबल से लागू पंक्तियों की तलाश करनी चाहिए, और नेस्ट लूप या मर्ज उन्हें छोटी टेबल के साथ जोड़ देता है।


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