यादृच्छिक संख्या और प्रकार के साथ अप्रत्याशित परिणाम


16

मेरे पास एक सरल स्क्रिप्ट है जिसमें चार यादृच्छिक संख्याएं (1 से 4 तक) मिलती हैं और फिर मिलान करने वाले डेटाबेस_आईडी नंबर प्राप्त करने के लिए वापस मिलती है। जब मैं एक स्क्रिप्ट को LEFT JOIN से चलाता हूं, तो मुझे हर बार (अपेक्षित परिणाम) चार पंक्तियाँ मिलती हैं। हालाँकि, जब मैं इसे INNER JOIN के साथ चलाता हूं, तो मुझे अलग-अलग पंक्तियों की संख्या मिलती है - कभी दो, कभी आठ।

तार्किक रूप से, इसमें कोई अंतर नहीं होना चाहिए क्योंकि मुझे पता है कि डेटाबेस डेटाबेस के साथ पंक्तियाँ 1-4 sys.dat डेटाबेस में मौजूद हैं। और क्योंकि हम चार पंक्तियों के साथ यादृच्छिक संख्या तालिका से चयन कर रहे हैं (जैसा कि इसमें शामिल होने का विरोध किया गया है), वहाँ कभी भी चार पंक्तियों से अधिक नहीं होना चाहिए।

यह SQL Server 2012 और 2014 दोनों में होता है। INNER JOIN में अलग-अलग संख्या में पंक्तियों को वापस लाने के कारण क्या होता है?

/* Works as expected -- always four rows */

SELECT rando.RandomNumber, d.database_id
FROM 
  (SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber 
   FROM sys.databases WHERE database_id <= 4) AS rando
LEFT JOIN sys.databases d ON rando.RandomNumber = d.database_id;


/* Returns a varying number of rows */

SELECT rando.RandomNumber, d.database_id
FROM 
  (SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber 
   FROM sys.databases WHERE database_id <= 4) AS rando
INNER JOIN sys.databases d ON rando.RandomNumber = d.database_id;

/* Also returns a varying number of rows */

WITH rando AS (
  SELECT 1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
  FROM sys.databases WHERE database_id <= 4
)

SELECT r.RandomNumber, d.database_id
FROM rando AS r
INNER JOIN sys.databases d ON r.RandomNumber = d.database_id;

3
हमेशा 4 पंक्तियों को प्राप्त करने का एक और तरीका: SELECT TOP (4) d.database_id FROM sys.databases AS d CROSS JOIN (VALUES (1),(2),(3),(4)) AS multi (i) WHERE d.database_id <= 4 ORDER BY CHECKSUM(NEWID()) ;मुझे लगता है कि यह ठीक काम करता है क्योंकि गैर-नियतात्मक फ़ंक्शन के मूल्य में कोई शामिल नहीं है।
ypercube y 17

जवाबों:


9

अतिरिक्त चयन को जोड़कर यह गणना स्केलर मूल्यांकन को योजना में गहराई से धकेलता है और सम्मिलित होने का अनुमान देता है, शीर्ष पर गणना स्केलर फिर पहले वाले को संदर्भित करता है।

SELECT rando.RandomNumber, d.database_id
FROM 
  (SELECT ( SELECT 1 + ABS(CHECKSUM(NEWID())) % (4)) AS RandomNumber 
   FROM sys.databases WHERE database_id <= 4) AS rando
INNER JOIN sys.databases d ON rando.RandomNumber = d.database_id

|--Compute Scalar(DEFINE:([Expr1071]=[Expr1070]))

|--Compute Scalar(DEFINE:([Expr1070]=(1)+abs(checksum(newid()))%(4)))

अभी भी खुदाई में है कि यह करने के लिए इतनी देर क्यों इंतजार कर रहा है, लेकिन वर्तमान में पॉल व्हाइट ( https://sql.kiwi/2012/09/compute-scalars-expressions-and-execution-plan-peritance.html ) द्वारा इस पोस्ट को पढ़ रहा है । शायद इसका इस तथ्य से कोई लेना-देना है कि NEWID नियतात्मक नहीं है?


12

यह कुछ जानकारी दे सकता है जब तक कि साइट के लोगों में से किसी एक को भी झंकार नहीं आती।

मैंने यादृच्छिक परिणामों को एक अस्थायी तालिका में डाल दिया है और मुझे लगातार 4 परिणाम मिलते हैं, भले ही वह शामिल प्रकार का हो।

/* Works as expected -- always four rows */

DECLARE @Rando table
(
    RandomNumber int
);

INSERT INTO
    @Rando
(
    RandomNumber
)
-- This generates 4 random numbers from 1 to 4, endpoints inclusive
SELECT
    1 + ABS(CHECKSUM(NEWID())) % (4) AS RandomNumber
FROM
    sys.databases
WHERE
    database_id <= 4;

SELECT
    *
FROM
    @Rando AS R;

SELECT
    rando.RandomNumber
,   d.database_id
FROM 
    @Rando AS rando
    LEFT JOIN 
        sys.databases d 
        ON rando.RandomNumber = d.database_id
ORDER BY 1,2;


/* Returns a varying number of rows */

SELECT rando.RandomNumber, d.database_id
FROM 
    @Rando AS rando
    INNER JOIN 
        sys.databases d 
        ON rando.RandomNumber = d.database_id
ORDER BY 1,2;

/* Also returns a varying number of rows */

WITH rando AS 
(
    SELECT * FROM @Rando AS rando
)
SELECT r.RandomNumber, d.database_id
FROM 
    rando AS r
    INNER JOIN 
        sys.databases d 
        ON r.RandomNumber = d.database_id
ORDER BY 1,2;

यदि मैं आपकी दूसरी क्वेरी और टेबल वैरिएबल के साथ भिन्नता के बीच क्वेरी प्लान्स की तुलना करता हूं, तो मैं देख सकता हूं कि दोनों के बीच एक निश्चित अंतर है। लाल एक्स No Join Predicateइतना है कि मेरे गुफाओं के डेवलपर मस्तिष्क के लिए वास्तव में अजीब लगता है

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

यदि मैं क्वेरी के यादृच्छिक बिट को स्थिर करता 1 % (4)हूं, तो मेरी योजना बेहतर दिखती है, लेकिन गणना स्केलर को समाप्त कर दिया गया, जिससे मुझे करीब से देखना पड़ा

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

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

2014

घर पर खेलने वालों के लिए, उपरोक्त क्वेरी योजना 2008 R2 उदाहरण से उत्पन्न की गई थी। 2014 की योजनाएं अलग दिखती हैं, लेकिन इसमें शामिल होने के बाद कम्प्यूट स्केलर ऑपरेशन बना रहता है।

यह निरंतर अभिव्यक्ति का उपयोग करके 2014 के लिए क्वेरी योजना है

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

यह न्यूड एक्सप्रेशन का उपयोग करते हुए 2014 के उदाहरण के लिए क्वेरी प्लान है।

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

यह जाहिरा तौर पर डिजाइन से है, कनेक्ट मुद्दा यहां। @PaulWhite के लिए धन्यवाद जो अस्तित्व में है।


1
ठीक है, बिल्कुल - यही हो रहा है, लेकिन यह निश्चित रूप से अपेक्षित नहीं है। नतीजे उस टी-एसक्यूएल से मेल नहीं खाते जो इसमें पास किया जा रहा है और इस तरह यह सवाल है।
ब्रेंट ओजर

यहां तक ​​कि एक रैंडम नंबर के साथ रैंडम नंबर को बदलने पर ज्वाइन ऑपरेटर को कोई ज्वाइन प्रेडिकेट नहीं देता है
जेम्स एंडरसन

ऐसा लगता है कि आप किसी चीज़ पर हैं। विकल्प (बल आदेश) का उपयोग करते हुए भी व्यवहार में परिवर्तन नहीं होता है - यादृच्छिक संख्या अभी भी अंतिम गणना की गई है ...
जेरेमिया पेस्का


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