लगातार स्कैन स्पूलिंग


14

मेरे पास कुछ दर्जन पंक्तियों वाली एक मेज है। सरलीकृत सेटअप निम्नलिखित है

CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);

और मेरे पास एक क्वेरी है जो इस तालिका को तालिका मूल्य निर्मित पंक्तियों (चर और स्थिरांक से बना) के एक सेट में मिलती है, जैसे

DECLARE @id1 int = 101, @id2 int = 105;

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (@id1, 'A'),
        (@id2, 'B')
    ) p([Id], [Code])
    FULL JOIN #data d ON d.[Id] = p.[Id];

क्वेरी निष्पादन योजना दिखा रही है कि ऑप्टिमाइज़र का निर्णय FULL LOOP JOINरणनीति का उपयोग करना है, जो उचित लगता है, क्योंकि दोनों इनपुट में बहुत कम पंक्तियाँ हैं। एक बात जिस पर मैंने ध्यान दिया (और सहमत नहीं हो सकता), हालांकि, यह है कि टीवीसी पंक्तियों को स्पूल किया जा रहा है (लाल बॉक्स में निष्पादन योजना का क्षेत्र देखें)।

लगातार स्कैन स्पूलिंग

क्यों अनुकूलक यहाँ स्पूल का परिचय देता है, इसे करने का क्या कारण है? स्पूल से आगे कुछ भी जटिल नहीं है। ऐसा लगता है कि यह आवश्यक नहीं है। इस मामले में कैसे छुटकारा पाएं, इसके संभावित तरीके क्या हैं?


उपरोक्त योजना प्राप्त की गई थी

Microsoft SQL सर्वर 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)


संबंधित सुझाव feedback.azure.com पर
i-one

जवाबों:


19

क्यों अनुकूलक यहाँ स्पूल का परिचय देता है, इसे करने का क्या कारण है? स्पूल से आगे कुछ भी जटिल नहीं है।

स्पूल से परे की चीज एक साधारण टेबल रेफरेंस नहीं है, जिसे केवल तब ही डुप्लिकेट किया जा सकता है जब लेफ्ट जॉइन / एंटी सेमी ज्वाइन विकल्प उत्पन्न होता है।

यह एक तालिका (लगातार स्कैन) की तरह लग सकता है , लेकिन आशावादी के लिए * यह खंड UNION ALLमें अलग पंक्तियों का एक VALUESहै।

अतिरिक्त जटिलता ऑप्टिमाइज़र के लिए स्पूल चुनना और स्रोत पंक्तियों को फिर से खेलना करने के लिए पर्याप्त है, और स्पूल को एक साधारण "टेबल गेट" के साथ बाद में प्रतिस्थापित न करें। उदाहरण के लिए, फुल जॉइन से प्रारंभिक परिवर्तन इस तरह दिखता है:

जल्दी योजना

सामान्य परिवर्तन द्वारा शुरू किए गए अतिरिक्त स्पूलों पर ध्यान दें। एक साधारण तालिका के ऊपर स्पूल को नियम द्वारा बाद में साफ किया जाता है SpoolGetToGet

यदि ऑप्टिमाइज़र का एक ही SpoolConstGetToConstGetनियम होता है, तो यह सिद्धांत रूप में आपकी इच्छानुसार काम कर सकता है।

इस मामले में कैसे छुटकारा पाएं, इसके संभावित तरीके क्या हैं?

एक वास्तविक तालिका (अस्थायी या परिवर्तनशील) का उपयोग करें, या पूर्ण रूप से परिवर्तन से मैन्युअल रूप से लिखें, उदाहरण के लिए:

WITH 
    p([Id], [Code]) AS
    (
        SELECT @id1, 'A'
        UNION ALL
        SELECT @id2, 'B'
    ),
    FullJoin AS
    (
        SELECT
            p.Code,
            d.[Status]
        FROM p
        LEFT JOIN #data d 
            ON d.[Id] = p.[Id]
        UNION ALL
        SELECT
            NULL,
            D.[Status]
        FROM #data AS D
        WHERE NOT EXISTS
        (
            SELECT *
            FROM p
            WHERE p.Id = D.Id
        )
    )
SELECT
    COALESCE(FullJoin.Code, 'X') AS Code,
    COALESCE(FullJoin.Status, 0) AS [Status]
FROM FullJoin;

मैनुअल फिर से लिखने की योजना:

मैनुअल फिर से लिखना योजना

इसकी मूल लागत 0.0067201 यूनिट है, जो मूल के लिए 0.0203412 इकाइयों के साथ है।


* यह एक रूपांतरित वृक्ष (TF 8605) LogOp_UnionAllमें देखा जा सकता है । में इनपुट ट्री (TF 8606) यह एक है । परिवर्तित ट्री शो पार्स, सामान्य, algebrization, बंधन, और कुछ अन्य प्रारंभिक काम करने के बाद अनुकूलक अभिव्यक्ति तत्वों का पेड़। इनपुट ट्री निषेध सामान्य फॉर्म (NNF परिवर्तित), क्रम निरंतर गिर, और कुछ अन्य बिट्स और bobs के लिए रूपांतरण के बाद तत्वों को दर्शाता है। एनएनएफ कन्वर्ट में लॉजिकल यूनियनों को ध्वस्त करने के लिए तर्क शामिल हैं और अन्य चीजों के अलावा आम टेबल मिलती है।LogOp_ConstTableGet


3

टेबल स्पूल बस VALUESक्लॉज में मौजूद ट्यूपल्स के दो सेटों में से एक टेबल बना रहा है ।

आप उन मूल्यों को पहले एक अस्थायी तालिका में डालकर स्पूल को समाप्त कर सकते हैं, जैसे:

DROP TABLE IF EXISTS #data;
CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);

DROP TABLE IF EXISTS #p;
CREATE TABLE #p
(
    Id int NOT NULL
    , Code char(1) NOT NULL
);

DECLARE @id1 int = 101, @id2 int = 105;

INSERT INTO #p (Id, Code)
VALUES
        (@id1, 'A'),
        (@id2, 'B');


SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM #p p
    FULL JOIN #data d ON d.[Id] = p.[Id];

आपकी क्वेरी के लिए निष्पादन योजना को देखते हुए, हम देखते हैं कि आउटपुट सूची में दो कॉलम हैं जो Unionउपसर्ग का उपयोग करते हैं ; यह संकेत है कि स्पूल एक यूनियन स्रोत से एक तालिका बना रहा है:

यहाँ छवि विवरण दर्ज करें

जुड़ने के प्रत्येक "पक्ष" के लिए एक बार दो बार FULL OUTER JOINमानों तक पहुंचने के लिए SQL सर्वर की आवश्यकता होती है p। स्पूल बनाने से स्पंदन किए गए डेटा तक पहुंचने के लिए परिणामस्वरूप आंतरिक लूप जुड़ते हैं।

दिलचस्प बात यह है, अगर आप की जगह FULL OUTER JOINएक साथ LEFT JOINऔर एक RIGHT JOINहै, और UNIONपरिणाम एक साथ, एसक्यूएल सर्वर एक स्पूल उपयोग नहीं करता।

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (101, 'A'),
        (105, 'B')
    ) p([Id], [Code])
    LEFT JOIN #data d ON d.[Id] = p.[Id]
UNION
SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (101, 'A'),
        (105, 'B')
    ) p([Id], [Code])
    RIGHT JOIN #data d ON d.[Id] = p.[Id];

यहाँ छवि विवरण दर्ज करें

ध्यान दें, मैं UNIONउपरोक्त क्वेरी का उपयोग करने का सुझाव नहीं दे रहा हूं ; इनपुट के बड़े सेट के लिए, यह FULL OUTER JOINआपके पास पहले से मौजूद सरल से अधिक कुशल नहीं हो सकता है।


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