समारोह लटका हुआ है अशक्त केस ऑपरेशन के साथ


9

मैंने एक ऐसा फंक्शन बनाया, जो एक शुरुआत और अंतिम तिथि को स्वीकार करता है, जिसमें अंतिम तिथि वैकल्पिक होती है। मैंने तब CASEप्रारंभ तिथि का उपयोग करने के लिए फ़िल्टर में लिखा था यदि कोई अंतिम तिथि नहीं बीतती है।

CASE WHEN @dateEnd IS NULL
    THEN @dateStart
    ELSE @dateEnd
END

जब मैं डेटा के सबसे हाल के महीने के लिए फ़ंक्शन को कॉल करता हूं:

SELECT * FROM theFunction ('2013-06-01', NULL)

... क्वेरी लटकी हुई है। यदि मैं अंतिम तिथि निर्दिष्ट करता हूं:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')

... परिणाम सामान्य रूप से लौटाया जाता है। मैंने फ़ंक्शन से कोड लिया और इसे क्वेरी विंडो के अंदर ठीक से चलाया। मैं इस मुद्दे को भी नकल नहीं कर सकता। एक क्वेरी की तरह:

SELECT * FROM theFunction ('2013-04-01', '2013-06-01')

... ठीक भी काम करता है।

क्या क्वेरी (नीचे) में कुछ भी है जो फ़ंक्शन को NULLअंतिम तिथि के लिए पारित होने पर लटका देने का कारण हो सकता है ?

एसक्यूएल फिडल


क्या आप अधिक तर्क पोस्ट कर सकते हैं? आपके पास जो कुछ भी है उससे समस्या पैदा नहीं होनी चाहिए।
केनेथ फिशर

3
यदि आप के CASEसाथ प्रतिस्थापित करते हैं COALESCE(@dateEnd,@dateStart), तो क्या समस्या अभी भी दिखाई देती है?
ypercube y

2
और के साथ ISNULL()?
ypercube y

3
क्या यह व्यस्त है या किसी चीज पर इंतजार कर रहा है? जबकि यह "त्रिशंकु" है क्या SELECT task_state FROM sys.dm_os_tasks WHERE session_id = x दिखाता है? यदि यह RUNNINGराज्य में बहुत समय बिताता है तो उस सत्र में किस प्रकार के इंतजार हो रहे हैं sys.dm_os_waiting_tasks?
मार्टिन स्मिथ

1
@ypercube के साथ कोई सुधार नहीं हुआ COALESCEISNULLठीक कर दिया।
कर्मी

जवाबों:


7

आपकी प्रारंभिक क्वेरी का हिस्सा निम्नानुसार है।

  FROM   [dbo].[calendar] a
          LEFT JOIN [dbo].[colleagueList] b
            ON b.[Date] = a.d
   WHERE  DAY(a.[d]) = 1
          AND a.[d] BETWEEN @dateStart AND COALESCE(@dateEnd,@dateStart) 

योजना का वह भाग नीचे दिखाया गया है

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

आपकी संशोधित क्वेरी BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)में इसी शामिल होने के लिए है

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

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

 a.[d] BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart) 
 a.[d] BETWEEN '2013-06-01' AND ISNULL(NULL,'2013-06-01') 
 a.[d] BETWEEN '2013-06-01' AND '2013-06-01'
 a.[d] = '2013-06-01'

और जैसा कि एक सम्‍मिलित है विधेय b.[Date] = a.dको सम्‍मिलित करें एक समता को सम्‍मिलित दर्शाता है b.[Date] = '2013-06-01'। परिणामस्वरूप 28,393पंक्तियों का कार्डिनैलिटी अनुमान बहुत सटीक होने की संभावना है।

के लिए CASE/ COALESCEसंस्करण जब @dateStartऔर @dateEndएक ही मूल्य तो यह सरल ही समानता अभिव्यक्ति के लिए ठीक हैं और एक ही योजना देता है, लेकिन जब @dateStart = '2013-06-01'और @dateEnd IS NULLयह केवल जहाँ तक चला जाता है

a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END

यह भी एक निहित भविष्यवाणी के रूप में लागू होता है ColleagueList। इस बार पंक्तियों की अनुमानित संख्या 79.8पंक्तियाँ हैं।

अगला साथ है

   LEFT JOIN colleagueTime
     ON colleagueTime.TC_DATE = colleagueList.Date
        AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10)) 

colleagueTimeएक 3,249,590पंक्ति तालिका है जो (फिर से) स्पष्ट रूप से कोई उपयोगी अनुक्रमित के साथ एक ढेर है।

अनुमानों में यह विसंगति इस्तेमाल की गई पसंद को प्रभावित करती है। ISNULLयोजना एक हैश में शामिल होने कि सिर्फ एक बार तालिका को स्कैन करता है चुनता है। COALESCEयोजना एक नेस्टेड छोरों में शामिल होने के लिए चुनता है और अनुमान है कि यह अभी भी सिर्फ एक बार तालिका स्कैन और परिणाम स्पूल और 78 बार यह पुनः चलाने के लिए सक्षम होने के लिए की आवश्यकता होगी। यानी यह अनुमान है कि सहसंबद्ध पैरामीटर नहीं बदलेगा।

इस तथ्य से कि नेस्टेड छोरों की योजना दो घंटे बाद भी चल रही थी, इसके खिलाफ एकल स्कैन की धारणा colleagueTimeअत्यधिक गलत होने की संभावना है।

दो जोड़ों के बीच पंक्तियों की अनुमानित संख्या इतनी कम क्यों है, इसके बारे में मुझे यकीन नहीं है कि हम तालिकाओं पर आंकड़े देख सकते हैं। एक ही तरीका है कि मैं अनुमानित पंक्ति गणना को तिरछा करने में कामयाब रहा कि मेरे परीक्षण में बहुत अधिक NULLपंक्तियों का भार शामिल था (इससे अनुमानित पंक्ति संख्या कम हो गई, जबकि पंक्तियों की वास्तविक संख्या समान बनी रही)।

COALESCEमेरे परीक्षण डेटा के साथ योजना में अनुमानित पंक्ति गणना के क्रम में थी

number of rows matching >= condition * 30% * (proportion of rows in the table not null)

या SQL में

SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
                                                  WHEN [Date] >= '2013-06-01' THEN 1
                                                END) * 0.30 )
FROM   [dbo].[colleagueList] 

लेकिन यह आपकी टिप्पणी के अनुसार नहीं है कि कॉलम में कोई NULLमूल्य नहीं है।


"क्या आपके पास उस तालिका में दिनांक स्तंभ में NULL मानों का अनुपात बहुत अधिक है?" मेरे पास NULLउन तालिकाओं में तारीखों के लिए कोई मूल्य नहीं है ।
कर्मीट

@FreshPrinceOfSO - यह एक अफ़सोस की बात है। मुझे अभी तक इस बारे में कोई जानकारी नहीं है कि दो अनुमानों में इतनी बड़ी विसंगति क्यों है। परीक्षणों में मैंने बिटमैप फ़िल्टर किया और अतिरिक्त विधेय ने कार्डिनिटी के अनुमानों में परिवर्तन नहीं किया, शायद यह यहाँ है।
मार्टिन स्मिथ

@FreshPrinceOfSO - हालांकि अगर आपको यह लगा कि आंकड़ों की स्क्रिप्टिंग करना मुझे पसंद है और मैं इसका पता लगा सकता हूं।
मार्टिन स्मिथ

मैं 2008R2 पर हूं; जब मुझे स्कीम चुनने के लिए मिलता है , dboतो सूचीबद्ध नहीं किया जाता है। बस अन्य स्कीमा जिनका मैं उपयोग नहीं करता हूं।
Kermit

4

ऐसा लगता है जैसे डेटा प्रकारों के साथ कोई समस्या थी। ISNULLमुद्दा तय किया (धन्यवाद ypercube )। कुछ शोधों के बाद, उस कथन COALESCEके बराबर है CASEजो मैं उपयोग कर रहा था:

CASE
   WHEN (expression1 IS NOT NULL) THEN expression1
   WHEN (expression2 IS NOT NULL) THEN expression2
   ...
   ELSE expressionN
END

पॉल व्हाइट बताते हैं कि:

COALESCE( expression [ ,...n ] ) उच्चतम डेटा प्रकार पूर्वता के साथ अभिव्यक्ति का डेटा प्रकार लौटाता है।

ISNULL(check_expression, replacement_value) check_expression के समान प्रकार देता है।

किसी भी डेटा प्रकार के मुद्दों से बचने के लिए, यह ISNULLकेवल दो अभिव्यक्तियों से निपटने के लिए उपयोग करने के लिए उपयुक्त कार्य है।

XML योजना अंश

एक्सएमएल योजना का उपयोग CASE, अभिव्यक्ति 2 है NULL:

SELECT * FROM theFunction ('2013-06-01', NULL)
<ScalarOperator ScalarString="CASE WHEN (1) THEN '2013-06-01' ELSE NULL END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Const ConstValue="(1)"/>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="'2013-06-01'"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

एक्सएमएल योजना का उपयोग CASE, अभिव्यक्ति 2 एक तारीख है:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
      </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

एक्सएमएल योजना का उपयोग ISNULL, अभिव्यक्ति 2 है NULL:

SELECT * FROM theFunction ('2013-06-01', NULL)
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

एक्सएमएल योजना का उपयोग ISNULL, अभिव्यक्ति 2 एक तारीख है:

SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
<ScalarOperator ScalarString="CASE WHEN [Expr1035]=(0) THEN NULL ELSE [Expr1036] END">
  <IF>
    <Condition>
      <ScalarOperator>
        <Compare CompareOp="EQ">
          <ScalarOperator>
            <Identifier>
              <ColumnReference Column="Expr1035"/>
            </Identifier>
          </ScalarOperator>
          <ScalarOperator>
            <Const ConstValue="(0)"/>
          </ScalarOperator>
        </Compare>
      </ScalarOperator>
    </Condition>
    <Then>
      <ScalarOperator>
        <Const ConstValue="NULL"/>
      </ScalarOperator>
    </Then>
    <Else>
      <ScalarOperator>
        <Identifier>
          <ColumnReference Column="Expr1036"/>
        </Identifier>
      </ScalarOperator>
    </Else>
  </IF>
</ScalarOperator>

लेकिन यह स्पष्ट नहीं करता है कि इसके लिए ठीक क्यों काम किया SELECT * FROM theFunction ('2013-06-01', '2013-06-01')। अभिव्यक्ति डेटाटाइप अभी भी समान है। और दोनों पैरामीटर dateवैसे भी डेटाटाइप हैं । क्या आप निष्पादन योजनाओं को देख सकते हैं?
मार्टिन स्मिथ

@MartinSmith यहाँ क्वेरी के लिए योजना है जो एक परिणाम देता है। जब दूसरी अभिव्यक्ति हो तो मेरे पास कोई योजना नहीं है NULL
कर्मिट

भाव के अंदर कास्टिंग का CASEभी कोई प्रभाव नहीं था, क्वेरी अभी भी लटका हुआ है।
कर्मीट

2
दूसरे मामले के लिए कोई योजना कैसे आए? क्या यह सिर्फ इसलिए है क्योंकि क्वेरी कभी खत्म नहीं होती है? यदि ऐसा है तो क्या आप एक अनुमानित योजना प्राप्त कर सकते हैं? आश्चर्य है कि यदि विभिन्न अभिव्यक्तियाँ कार्डिनैलिटी के अनुमानों को बदल देती हैं और आप एक अलग योजना के साथ समाप्त हो जाते हैं।
मार्टिन स्मिथ

3
ISNULLऐसा लगता है कि योजना दिखता बेहतर सरल करता है। यह एक साधारण समानता है, जो सहकर्मी की भविष्यवाणी पर आधारित है, [Date]='2013-06-01'जबकि CASEएक पर एक विधेय है [Date]>='2013-06-01' AND [Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END AND PROBE([Bitmap1067],[Date])। उस जोड़ से निकलने वाली अनुमानित पंक्तियाँ ISNULLसंस्करण के लिए 28,393 हैं लेकिन बहुत कम हैं79.8 के लिए CASEसंस्करण है जो प्रभाव योजना में बाद में चुनाव में शामिल हो। निश्चित नहीं है कि ऐसी विसंगति क्यों होगी।
मार्टिन स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.