SQL सर्वर को काउंट (*) परिणाम को इंट चर से तुलना करने से पहले int में बदलने की आवश्यकता क्यों है?


11

मेरे आवेदन में मेरे कई सवाल हैं, जहाँ क्लॉज़ होने पर, मैंने इंट वेरिएबल के साथ काउंट एग्रेट फंक्शन की तुलना की है। क्वेरी योजनाओं में, मैं तुलना से पहले एक implicit_convert देख सकता हूं। मैं जानना चाहता हूं कि ऐसा क्यों होता है क्योंकि एसक्यूएल सर्वर प्रलेखन के अनुसार, काउंटर फ़ंक्शन का रिटर्न प्रकार अंतर है। तो दो अंतर मूल्यों की तुलना के लिए एक अंतर्निहित रूपांतरण क्यों होना चाहिए?

निम्नलिखित एक ऐसी क्वेरी योजना का एक हिस्सा है जहाँ @IdCount को एक अंतर चर के रूप में परिभाषित किया गया है।

| --Filter (जहां: ([Expr1022] = [@ IdCount]))    
 | --कंप्यूट स्केलर (DEFINE: ([Expr1022] = CONVERT_IMPLICIT (int, [Expr1028], 0))) 
  | --स्ट्रीम एग्रीगेट (ग्रुप बाय: ([MOCK_DB]। [Dbo]। [स्कोप]]

जवाबों:


17

तथ्य यह है कि आप एक integerचर के खिलाफ तुलना कर रहे हैं अप्रासंगिक है।

COUNTहमेशा की योजना में एक परिणाम के लिए लेबल CONVERT_IMPLICIT(int,[ExprNNNN],0))कहाँ ExprNNNNहै, जिसके परिणाम का प्रतिनिधित्व करता है COUNT

मेरी धारणा हमेशा से यही रही है कि कोड COUNTकेवल उसी कोड को कॉल करने के लिए समाप्त होता है, COUNT_BIGऔर bigintउस बैक के परिणाम को बदलने के लिए कास्ट आवश्यक है int

वास्तव COUNT_BIG(*)में क्वेरी प्लान से भी अलग नहीं है COUNT(*)। दोनों के रूप में दिखाते हैं Scalar Operator(Count(*))

COUNT_BIG(nullable_column)निष्पादन योजना में प्रतिष्ठित है, COUNT(nullable_column) लेकिन बाद में अभी भी एक निहित कलाकारों को वापस मिल जाता है int

कुछ सबूत हैं कि यह मामला नीचे है।

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
, E16(N) AS (SELECT 1 FROM E8 a, E8 b)  -- 1*10^16 or 10,000,000,000,000,000 rows
, T(N) AS (SELECT TOP (2150000000) 
                  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM E16)
SELECT COUNT(CASE WHEN N < 2150000000 THEN 1 END)
FROM T 
OPTION (MAXDOP 1)

मेरे डेस्कटॉप पर चलने के लिए लगभग 7 मिनट लगते हैं और निम्नलिखित को वापस करता है

Msg 8115, स्तर 16, राज्य 2, पंक्ति 1
अंकगणितीय अतिप्रवाह त्रुटि अभिव्यक्ति को डेटा प्रकार int में परिवर्तित करना।
चेतावनी: शून्य मान एक समग्र या अन्य SET ऑपरेशन द्वारा समाप्त हो जाता है।

जो इंगित करता है कि ओवरफ्लो COUNTहोने के बाद int(2147483647 पर) जारी रहने के बाद जारी रहना चाहिए और अंतिम पंक्ति (2150000000) को COUNTऑपरेटर द्वारा संसाधित किया गया था जिससे संदेश NULLवापस आ रहा था।

तुलना के माध्यम से COUNTअभिव्यक्ति की जगह SUM(CASE WHEN N < 2150000000 THEN 1 END)रिटर्न के साथ

Msg 8115, स्तर 16, राज्य 2, पंक्ति 1
अंकगणितीय अतिप्रवाह त्रुटि अभिव्यक्ति को डेटा प्रकार int में परिवर्तित करना।

जिसके ANSIबारे में कोई चेतावनी नहीं है NULL। जिससे मैं निष्कर्ष निकालता हूं कि इस मामले में एकत्रीकरण के दौरान 2,150,000,000 पंक्तियों तक पहुंचने से पहले ही अतिप्रवाह हुआ था।


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