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


17

यह एक विशुद्ध रूप से अकादमिक प्रश्न है, इस कारण यह समस्या पैदा नहीं कर रहा है और मैं व्यवहार के लिए किसी भी स्पष्टीकरण को सुनने के लिए इच्छुक हूं।

एक मानक मुद्दा इट्ज़िक बेन-गण क्रॉस सीटीई टैली तालिका में शामिल हों:

USE [master]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[TallyTable] 
(   
    @N INT
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN 
(
    WITH 
    E1(N) AS 
    (
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
    )                                       -- 1*10^1 or 10 rows
    , E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
    , E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
    , E8(N) AS (SELECT 1 FROM E4 a, E4 b)   -- 1*10^8 or 100,000,000 rows

    SELECT TOP (@N) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM E8 
)
GO

एक क्वेरी जारी करें जो 1 मिलियन पंक्ति संख्या तालिका बनाएगी:

SELECT
    COUNT(N)
FROM
    dbo.TallyTable(1000000) tt

इस क्वेरी के लिए समानांतर निष्पादन योजना पर एक नज़र डालें:

समानांतर निष्पादन योजना

ध्यान दें कि जमा धाराओं ऑपरेटर से पहले 'वास्तविक' पंक्ति की गिनती 1,004,588 है। इकट्ठा धाराओं के बाद पंक्ति संख्या अपेक्षित 1,000,000 है। अजनबी अभी भी, मूल्य सुसंगत नहीं है और चलाने के लिए अलग-अलग होगा। COUNT का परिणाम हमेशा सही होता है।

गैर-समानांतर योजना को मजबूर करते हुए फिर से प्रश्न जारी करें:

SELECT
    COUNT(N)
FROM
    dbo.TallyTable(1000000) tt
OPTION (MAXDOP 1)

इस बार सभी संचालक सही 'वास्तविक' पंक्ति को दर्शाते हैं।

गैर-समानांतर निष्पादन योजना

मैं 2005SP3 और 2008R2 पर अब तक यह कोशिश कर चुका हूं, दोनों पर समान परिणाम। क्या यह कारण हो सकता है के रूप में किसी भी विचार?

जवाबों:


12

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

एक परिणाम के रूप में, आप अक्सर इस तरह की पंक्ति गणना अंतर देखेंगे जहां उप-पेड़ की पूरी संभावित पंक्तियों से कम वास्तव में आवश्यक है। इस मामले में, TOP 'प्रारंभिक अंत' के लिए निष्पादन लाता है।

अधिक जानकारी:


10

मुझे लगता है कि मेरे पास इसके लिए एक आंशिक स्पष्टीकरण हो सकता है लेकिन कृपया इसे शूट करने या किसी भी विकल्प को पोस्ट करने के लिए स्वतंत्र महसूस करें। निष्पादन योजना में TOP के प्रभाव को उजागर करके @MartinSmith निश्चित रूप से कुछ पर है।

सीधे शब्दों में कहें, 'एक्चुअल रो काउंट' उन पंक्तियों की गिनती नहीं है जो एक ऑपरेटर प्रक्रियाओं की होती है, यह ऑपरेटर के गेटनेक्स्ट () विधि को कहा जाता है।

BOL से लिया गया :

भौतिक ऑपरेटर डेटा को आरंभ, एकत्रित और बंद करते हैं। विशेष रूप से, भौतिक ऑपरेटर निम्नलिखित तीन विधि कॉलों का उत्तर दे सकता है:

  • Init (): Init () विधि एक भौतिक ऑपरेटर को खुद को प्रारंभ करने और किसी भी आवश्यक डेटा संरचनाओं को सेट करने का कारण बनता है। भौतिक ऑपरेटर कई Init () कॉल प्राप्त कर सकता है, हालांकि आमतौर पर एक भौतिक ऑपरेटर केवल एक ही प्राप्त करता है।
  • गेटनेक्स्ट (): गेटनेक्स्ट () विधि एक भौतिक ऑपरेटर को डेटा की पहली या बाद की पंक्ति प्राप्त करने का कारण बनता है। भौतिक ऑपरेटर शून्य या कई गेटनेक्स्ट () कॉल प्राप्त कर सकता है।
  • क्लोज़ (): क्लोज़ () विधि एक भौतिक ऑपरेटर को कुछ क्लीन-अप ऑपरेशन करने और खुद को बंद करने का कारण बनता है। एक भौतिक ऑपरेटर केवल एक बंद () कॉल प्राप्त करता है।

गेटनेक्स्ट () विधि डेटा की एक पंक्ति लौटाती है, और जितनी बार इसे कहा जाता है वह Showplan आउटपुट में RealRows के रूप में प्रकट होता है जो SET STATISTICS PROFILE ON या SET STATISTICS XML ON का उपयोग करके निर्मित होता है।

पूर्णता के लिए, समानांतर ऑपरेटरों पर एक छोटी पृष्ठभूमि उपयोगी है। काम एक समानांतर योजना में कई धाराओं के लिए वितरण धारा द्वारा वितरित किया जाता है या स्ट्रीम ऑपरेटरों को वितरित करता है। ये चार तंत्रों में से एक का उपयोग करके धागे के बीच पंक्तियों या पृष्ठों को वितरित करते हैं:

  • हैश पंक्ति में स्तंभों के हैश के आधार पर पंक्तियों को वितरित करता है
  • राउंड-रॉबिन एक लूप में धागे की सूची के माध्यम से पुनरावृत्ति करके पंक्तियों को वितरित करता है
  • प्रसारण सभी थ्रेड्स को सभी पृष्ठ या पंक्तियाँ वितरित करता है
  • डिमांड विभाजन का उपयोग केवल स्कैन के लिए किया जाता है। थ्रेड्स स्पिन करते हैं, ऑपरेटर से डेटा के एक पृष्ठ का अनुरोध करते हैं, इसे संसाधित करते हैं और जब किया जाता है तो एक और पृष्ठ का अनुरोध करते हैं।

पहले वितरित स्ट्रीम ऑपरेटर (योजना में सबसे सही) एक निरंतर स्कैन से उत्पन्न होने वाली पंक्तियों पर मांग विभाजन का उपयोग करता है। कुल 10 'वास्तविक पंक्तियों' के लिए तीन धागे हैं जो गेटनेक्स्ट () 6, 4 और 0 बार कहते हैं:

<RunTimeInformation>
       <RunTimeCountersPerThread Thread="2" ActualRows="6" ActualEndOfScans="1" ActualExecutions="1" />
       <RunTimeCountersPerThread Thread="1" ActualRows="4" ActualEndOfScans="1" ActualExecutions="1" />
       <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
 </RunTimeInformation>

अगले वितरण ऑपरेटर में हमारे पास तीन धागे हैं, इस बार कुल 100 के लिए गेटनेक् () के लिए 50, 50 और 0 कॉल हैं:

<RunTimeInformation>
    <RunTimeCountersPerThread Thread="2" ActualRows="50" ActualEndOfScans="1" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="1" ActualRows="50" ActualEndOfScans="1" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
</RunTimeInformation>

यह अगले समानांतर ऑपरेटर पर है कि कारण और स्पष्टीकरण संभवतः प्रकट होता है।

<RunTimeInformation>
    <RunTimeCountersPerThread Thread="2" ActualRows="1" ActualEndOfScans="0" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="1" ActualRows="10" ActualEndOfScans="0" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
</RunTimeInformation>

इसलिए अब हमारे पास गेटनेक्स्ट () में 11 कॉल हैं, जहां हम 10 देखने की उम्मीद कर रहे थे।

संपादित करें: 2011-11-13

इस बिंदु पर अटक, मैं क्लस्टर इंडेक्स में चैप्स के साथ उत्तर के लिए हॉकिंग गया और @ मायकेवल्श ने यहां @SQLKiwi को निर्देशित किया ।


7

1,004,588 एक आंकड़ा है जो मेरे परीक्षण में भी बहुत फसल लेता है।

मैं इसे नीचे कुछ सरल योजना के लिए भी देखता हूं।

WITH 
E1(N) AS 
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)                                       -- 1*10^1 or 10 rows
, E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
, E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
SELECT * INTO #E4 FROM E4;

WITH E8(N) AS (SELECT 1 FROM #E4 a, #E4 b),
Nums(N) AS (SELECT  TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM E8 )
SELECT COUNT(N) FROM Nums

DROP TABLE #E4

योजना

निष्पादन योजना में रुचि के अन्य आंकड़े हैं

+----------------------------------+--------------+--------------+-----------------+
|                                  | Table Scan A | Table Scan B | Row Count Spool |
+----------------------------------+--------------+--------------+-----------------+
| Number Of Executions             | 2            |            2 |             101 |
| Actual Number Of Rows - Total    | 101          |        20000 |         1004588 |
| Actual Number Of Rows - Thread 0 | -            |              |                 |
| Actual Number Of Rows - Thread 1 | 95           |        10000 |          945253 |
| Actual Number Of Rows - Thread 2 | 6            |        10000 |           59335 |
| Actual Rebinds                   | 0            |            0 |               2 |
| Actual Rewinds                   | 0            |            0 |              99 |
+----------------------------------+--------------+--------------+-----------------+

मेरा अनुमान सिर्फ इतना है कि क्योंकि कार्यों को समानांतर एक कार्य में संसाधित किया जा रहा है, मध्य उड़ान प्रसंस्करण पंक्तियों में है जब अन्य एक लाख जमा पंक्ति धाराओं ऑपरेटर को वितरित करता है ताकि अतिरिक्त पंक्तियों को संभाला जा सके। इसके अलावा इस लेख से पंक्तियों को बफ़र किया जाता है और बैचों में इस पुनरावृत्ति में वितरित किया जाता है, इसलिए यह काफी संभावना है कि संसाधित होने वाली पंक्तियों की संख्या TOPकिसी भी घटना में विनिर्देश को हिट करने के बजाय अधिक हो जाएगी ।

संपादित करें

बस इसे थोड़ा और विस्तार से देख रहे हैं। मैंने देखा कि मैं 1,004,588ऊपर उद्धृत पंक्ति की तुलना में अधिक विविधता प्राप्त कर रहा था, इसलिए 1,000 पुनरावृत्तियों के लिए एक लूप में ऊपर की क्वेरी को चलाया और वास्तविक निष्पादन योजनाओं पर कब्जा कर लिया। 81 परिणामों के लिए जिसके लिए समानता की डिग्री शून्य थी, निम्नलिखित आंकड़े दिए।

count       Table Scan A: Total Actual Row Spool - Total Actual Rows
----------- ------------------------------ ------------------------------
352         101                            1004588
323         102                            1004588
72          101                            1003565
37          101                            1002542
35          102                            1003565
29          101                            1001519
18          101                            1000496
13          102                            1002542
5           9964                           99634323
5           102                            1001519
4           9963                           99628185
3           10000                          100000000
3           9965                           99642507
2           9964                           99633300
2           9966                           99658875
2           9965                           99641484
1           9984                           99837989
1           102                            1000496
1           9964                           99637392
1           9968                           99671151
1           9966                           99656829
1           9972                           99714117
1           9963                           99629208
1           9985                           99847196
1           9967                           99665013
1           9965                           99644553
1           9963                           99623626
1           9965                           99647622
1           9966                           99654783
1           9963                           99625116

यह देखा जा सकता है कि 1,004,588 अब तक का सबसे आम परिणाम था, लेकिन 3 मौकों पर सबसे खराब स्थिति हुई और 100,000,000 पंक्तियों को संसाधित किया गया। देखा गया सबसे अच्छा मामला 1,000,496 पंक्ति गणना था, जो 19 बार हुआ।

पुन: पेश करने के लिए पूर्ण स्क्रिप्ट इस उत्तर के संशोधन 2 के निचले भाग में है (इसे 2 से अधिक प्रोसेसर वाले सिस्टम पर चलाने के लिए इसे ट्विक करने की आवश्यकता होगी)।


1

मेरा मानना ​​है कि समस्या इस तथ्य से आती है कि कई धाराएं एक ही पंक्ति को इस प्रक्रिया के आधार पर संसाधित कर सकती हैं कि कैसे धाराओं के बीच पंक्तियों को उकेरा जाता है।

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