EXISTS (Select 1…) vs EXISTS (Select *…) एक या दूसरा?


38

जब भी मुझे किसी तालिका में किसी पंक्ति के अस्तित्व की जाँच करने की आवश्यकता होती है, तो मैं हमेशा एक शर्त लिखता हूँ:

SELECT a, b, c
  FROM a_table
 WHERE EXISTS
       (SELECT *  -- This is what I normally write
          FROM another_table
         WHERE another_table.b = a_table.b
       )

कुछ अन्य लोग इसे लिखते हैं:

SELECT a, b, c
  FROM a_table
 WHERE EXISTS
       (SELECT 1   --- This nice '1' is what I have seen other people use
          FROM another_table
         WHERE another_table.b = a_table.b
       )

जब NOT EXISTSइसके बजाय की स्थिति है EXISTS: कुछ अवसरों में, मैं इसे एक LEFT JOINऔर अतिरिक्त शर्त (कभी-कभी एंटीजन कहलाता है ) के साथ लिख सकता हूं :

SELECT a, b, c
  FROM a_table
       LEFT JOIN another_table ON another_table.b = a_table.b
 WHERE another_table.primary_key IS NULL

मैं इसे टालने की कोशिश करता हूं क्योंकि मुझे लगता है कि अर्थ कम स्पष्ट है, विशेष रूप से तब जब आपका जो है primary_keyवह स्पष्ट नहीं है, या जब आपकी प्राथमिक कुंजी या आपकी सम्मिलित स्थिति मल्टी-कॉलम है (और आप आसानी से किसी एक कॉलम को भूल सकते हैं)। हालांकि, कभी-कभी आप किसी और द्वारा लिखे गए कोड को बनाए रखते हैं ... और यह बस वहां है।

  1. क्या SELECT 1इसके बजाय उपयोग करने के लिए कोई अंतर (शैली के अलावा) है SELECT *?
    क्या कोई कोने का मामला है जहां यह उसी तरह व्यवहार नहीं करता है?

  2. हालाँकि मैंने जो लिखा है वह (AFAIK) मानक SQL है: क्या विभिन्न डेटाबेस / पुराने संस्करणों के लिए ऐसा अंतर है?

  3. क्या एंटीजन लिखने में एक्सप्लोसिव पर कोई फायदा है?
    क्या समकालीन योजनाकार / आशावादी लोग इसे NOT EXISTSखंड से अलग मानते हैं ?


5
ध्यान दें कि PostgreSQL कॉलम के बिना चयन का समर्थन करता है, इसलिए आप बस लिख सकते हैं EXISTS (SELECT FROM ...)
राइटफोल्ड

1
मैं कुछ साल पहले SO पर लगभग एक ही सवाल पूछ रहा हूं: stackoverflow.com/questions/7710153/…
Erwin Brandstetter

जवाबों:


45

नहीं, सभी प्रमुख DBMS में (NOT) EXISTS (SELECT 1 ...)और दक्षता में कोई अंतर नहीं है (NOT) EXISTS (SELECT * ...)। मैंने अक्सर (NOT) EXISTS (SELECT NULL ...)इस्तेमाल होते हुए भी देखा है ।

कुछ में आप लिख भी सकते हैं (NOT) EXISTS (SELECT 1/0 ...)और परिणाम एक ही है - बिना किसी (शून्य से विभाजन) त्रुटि, जो यह साबित करता है कि वहां की अभिव्यक्ति का मूल्यांकन भी नहीं किया गया है।


LEFT JOIN / IS NULLएंटीजन विधि के बारे में , एक सुधार: यह इसके बराबर है NOT EXISTS (SELECT ...)

इस मामले में, NOT EXISTSबनामLEFT JOIN / IS NULL, आपको अलग-अलग निष्पादन योजनाएं मिल सकती हैं। उदाहरण के लिए MySQL में और ज्यादातर पुराने संस्करणों में (5.7 से पहले) योजनाएं काफी हद तक समान होंगी लेकिन समान नहीं हैं। अन्य DBMS (SQL Server, Oracle, Postgres, DB2) के आशावादी हैं - जहाँ तक मुझे पता है - इन 2 तरीकों को फिर से लिखने और दोनों के लिए समान योजनाओं पर विचार करने में अधिक या कम सक्षम है। फिर भी, इस तरह की कोई गारंटी नहीं है और अनुकूलन करते समय, अलग-अलग समकक्ष रीराइट्स से योजनाओं की जांच करना अच्छा है क्योंकि ऐसे मामले हो सकते हैं जो प्रत्येक ऑप्टिमाइज़र फिर से नहीं लिखता है (उदाहरण के लिए जटिल प्रश्न, कई जॉइन और / या व्युत्पन्न टेबल के साथ /। उपकुंजियों के अंदर उप-क्षेत्र, जहां कई तालिकाओं से स्थितियां, जुड़ने की स्थिति में उपयोग किए गए समग्र कॉलम) या उपलब्ध अनुक्रमणिका, सेटिंग्स आदि द्वारा ऑप्टिमाइज़र विकल्प और योजनाएं अलग-अलग प्रभावित होती हैं।

यह भी ध्यान दें कि USINGसभी DBMS (उदाहरण के लिए SQL सर्वर) में उपयोग नहीं किया जा सकता है। JOIN ... ONहर जगह अधिक सामान्य काम करता है।
और स्तंभों को तालिका नाम / उपनाम के साथ उपसर्ग करने की आवश्यकता होती SELECTहै, जब हम जुड़ते हैं तो त्रुटियों / अस्पष्टता से बचने के लिए।
मैं आम तौर पर शामिल किए गए कॉलम को IS NULLचेक में रखना पसंद करता हूं (हालांकि पीके या कोई भी अशक्त स्तंभ ठीक होगा, यह दक्षता के लिए उपयोगी हो सकता है जब LEFT JOINगैर-संकुल सूचकांक का उपयोग करने की योजना ):

SELECT a_table.a, a_table.b, a_table.c
  FROM a_table
       LEFT JOIN another_table 
           ON another_table.b = a_table.b
 WHERE another_table.b IS NULL ;

एंटिज़ेन्स के लिए एक तीसरी विधि भी है, जिसके उपयोग से NOT INलेकिन इसके अलग-अलग शब्दार्थ हैं (और परिणाम!) यदि अंदर की मेज का स्तंभ अशक्त है। इसका उपयोग पंक्तियों को छोड़कर NULL, पिछले 2 संस्करणों के बराबर क्वेरी बनाने के लिए किया जा सकता है :

SELECT a, b, c
  FROM a_table
 WHERE a_table.b NOT IN 
       (SELECT another_table.b
          FROM another_table
         WHERE another_table.b IS NOT NULL
       ) ;

यह भी आम तौर पर अधिकांश DBMS में इसी तरह की योजनाओं का उत्पादन करता है।


1
MySQL के हाल के संस्करणों तक [NOT] IN (SELECT ...), हालांकि, समकक्ष, बहुत खराब प्रदर्शन किया । इससे बचो!
रिक जेम्स

3
यह PostgreSQL के लिए सही नहीं हैSELECT *निश्चित रूप से अधिक काम कर रहा है। मैं सादगी का उपयोग करने की सलाह दूंगाSELECT 1
इवान कैरोल

11

ऐसे मामले में से एक श्रेणी है SELECT 1और SELECT *अधिक विशेष रूप से, एक हमेशा उन मामलों में अन्य, जबकि ज्यादातर नहीं होगा स्वीकार किया जाएगा - परस्पर विनिमय नहीं कर रहे हैं।

मैं उन मामलों के बारे में बात कर रहा हूं जहां आपको समूहबद्ध सेट की पंक्तियों के अस्तित्व की जांच करने की आवश्यकता है । यदि तालिका Tमें कॉलम हैं C1और C2आप किसी विशिष्ट स्थिति से मेल खाने वाले पंक्ति समूहों के अस्तित्व की जाँच कर रहे हैं, तो आप SELECT 1इस तरह का उपयोग कर सकते हैं :

EXISTS
(
  SELECT
    1
  FROM
    T
  GROUP BY
    C1
  HAVING
    AGG(C2) = SomeValue
)

लेकिन आप SELECT *उसी तरह से उपयोग नहीं कर सकते ।

वह महज एक वाक्यात्मक पहलू है। जहाँ दोनों विकल्पों को वाक्यविन्यास के रूप में स्वीकार किया जाता है, आपको सबसे अधिक संभावना होगी कि प्रदर्शन के मामले में कोई अंतर नहीं है या परिणाम वापस आ गए हैं, जैसा कि अन्य उत्तर में बताया गया है ।

टिप्पणियों के बाद अतिरिक्त नोट्स

ऐसा नहीं है कि कई डेटाबेस उत्पाद वास्तव में इस भेद का समर्थन करते हैं। SQL सर्वर, Oracle, MySQL और SQLite जैसे उत्पाद SELECT *बिना किसी त्रुटि के उपरोक्त क्वेरी में खुशी से स्वीकार करेंगे , जिसका अर्थ है कि वे SELECTएक विशेष तरीके से EXISTS का इलाज करते हैं ।

PostgreSQL एक RDBMS है जहां SELECT *विफल हो सकता है, लेकिन फिर भी कुछ मामलों में काम कर सकता है। विशेष रूप से, यदि आप पीके द्वारा समूह बना रहे हैं, तो SELECT *ठीक काम करेगा, अन्यथा यह संदेश के साथ विफल हो जाएगा:

त्रुटि: कॉलम "T.C2" को ग्रुप बाय क्लॉज में प्रकट होना चाहिए या एक समग्र फ़ंक्शन में उपयोग किया जाना चाहिए


1
अच्छे बिंदु, हालांकि यह बिल्कुल ऐसा मामला नहीं है जिसके बारे में मैं चिंतित था। यह एक वैचारिक अंतर दिखाता है । क्योंकि, जब आप GROUP BY, की अवधारणा *व्यर्थ है (या, कम से कम, स्पष्ट नहीं है)।
जोनलो

5

EXISTSक्लॉज को फिर से लिखने का एक दिलचस्प दिलचस्प तरीका, जिसके परिणामस्वरूप क्लीनर, और शायद कम भ्रामक क्वेरी, कम से कम SQL सर्वर में होगी:

SELECT a, b, c
  FROM a_table
 WHERE b = ANY
       (
          SELECT b
          FROM another_table
       );

एंटी-सेमी-जॉइन का संस्करण जैसा दिखेगा:

SELECT a, b, c
  FROM a_table
 WHERE b <> ALL
       (
          SELECT b
          FROM another_table
       );

दोनों आमतौर पर WHERE EXISTSया तो एक ही योजना के लिए अनुकूलित होते हैं WHERE NOT EXISTS, लेकिन इरादे अचूक होते हैं, और आपके पास कोई "अजीब" 1या नहीं होता है *

दिलचस्प है, के साथ जुड़े अशक्त जांच समस्याओं के NOT IN (...)लिए समस्याग्रस्त हैं <> ALL (...), जबकि NOT EXISTS (...)उस समस्या से ग्रस्त नहीं है। एक अशक्त स्तंभ के साथ निम्नलिखित दो तालिकाओं पर विचार करें:

IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
    DROP TABLE #t;
END;
CREATE TABLE #t 
(
    ID INT NOT NULL IDENTITY(1,1)
    , SomeValue INT NULL
);

IF OBJECT_ID('tempdb..#s') IS NOT NULL
BEGIN
    DROP TABLE #s;
END;
CREATE TABLE #s 
(
    ID INT NOT NULL IDENTITY(1,1)
    , SomeValue INT NULL
);

हम दोनों के साथ कुछ डेटा जोड़ देंगे, कुछ पंक्तियों के साथ जो मेल खाते हैं, और कुछ जो नहीं करते हैं:

INSERT INTO #t (SomeValue) VALUES (1);
INSERT INTO #t (SomeValue) VALUES (2);
INSERT INTO #t (SomeValue) VALUES (3);
INSERT INTO #t (SomeValue) VALUES (NULL);

SELECT *
FROM #t;
+ -------- + ----------- +
| आईडी | SomeValue |
+ -------- + ----------- +
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | नल |
+ -------- + ----------- +
INSERT INTO #s (SomeValue) VALUES (1);
INSERT INTO #s (SomeValue) VALUES (2);
INSERT INTO #s (SomeValue) VALUES (NULL);
INSERT INTO #s (SomeValue) VALUES (4);

SELECT *
FROM #s;
+ -------- + ----------- +
| आईडी | SomeValue |
+ -------- + ----------- +
| 1 | 1 |
| 2 | 2 |
| 3 | नल |
| 4 | 4 |
+ -------- + ----------- +

NOT IN (...)क्वेरी:

SELECT *
FROM #t 
WHERE #t.SomeValue NOT IN (
    SELECT #s.SomeValue
    FROM #s 
    );

निम्नलिखित योजना है:

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

क्वेरी तब कोई पंक्तियाँ नहीं लौटाती है क्योंकि NULL मान पुष्टि करने के लिए समानता को असंभव बनाते हैं।

यह क्वेरी, <> ALL (...)उसी योजना को दिखाती है और कोई पंक्तियाँ नहीं लौटाती:

SELECT *
FROM #t 
WHERE #t.SomeValue <> ALL (
    SELECT #s.SomeValue
    FROM #s 
    );

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

उपयोग करने वाला संस्करण NOT EXISTS (...), थोड़ा अलग योजना आकार दिखाता है, और पंक्तियों को वापस करता है:

SELECT *
FROM #t 
WHERE NOT EXISTS (
    SELECT 1
    FROM #s 
    WHERE #s.SomeValue = #t.SomeValue
    );

योजना:

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

उस क्वेरी के परिणाम:

+ -------- + ----------- +
| आईडी | SomeValue |
+ -------- + ----------- +
| 3 | 3 |
| 4 | नल |
+ -------- + ----------- +

यह <> ALL (...)समस्याग्रस्त परिणाम के रूप में बस के रूप में का उपयोग कर बनाता है NOT IN (...)


3
मुझे कहना होगा कि मुझे *अजीब नहीं लगता : मैंने EXISTS (SELECT * FROM t WHERE ...) एएस पढ़ा there is a _row_ in table _t_ that...। किसी भी तरह, मुझे विकल्प पसंद हैं, और तुम्हारा स्पष्ट रूप से पठनीय है। एक संदेह / चेतावनी: यदि bयह अशक्त है तो यह कैसे व्यवहार करेगा ? [मुझे बुरे अनुभव और कुछ छोटी रातें x IN (SELECT something_nullable FROM a_table)
हुईं

EXISTS आपको बताता है कि किसी तालिका में पंक्ति है या सही या गलत है। मौजूद है (द्वारा चुने जाने वाले (मान (शून्य)) x सच है। में है = किसी और में नहीं है <> सभी। ये 4 संभवतः मेल खाते हैं। (एक्स NULLs के साथ एक आरएचएस पंक्ति लेने के लिए) = किसी भी (मान (शून्य)) और (x) <> सभी (मान (शून्य)) अज्ञात / अशक्त हैं, लेकिन EXISTS (मान (शून्य)) सत्य है। (IN & = में समान "null चेक समस्याएँ हैं जो IN (...) [] से जुड़ी नहीं हैं ] <> ALL (...) "। कोई भी और सभी पुनरावृति OR & AND। लेकिन केवल" समस्याएं "हैं यदि आप उद्देश्य के अनुसार शब्दार्थ को व्यवस्थित नहीं करते हैं।) EXISTS के लिए इनका उपयोग करने की सलाह न दें। वे भ्रामक हैं। , "कम भ्रामक" नहीं।
21

@philliprxy - अगर मैं गलत हूं, तो मुझे इसे स्वीकार करने में कोई समस्या नहीं है। यदि आप ऐसा महसूस करते हैं तो अपने स्वयं के उत्तर को जोड़ने के लिए स्वतंत्र महसूस करें।
मैक्स वर्नोन

4

"प्रमाण" जो वे समान हैं (MySQL में) करना है

EXPLAIN EXTENDED
    SELECT EXISTS ( SELECT * ... ) AS x;
SHOW WARNINGS;

फिर के साथ दोहराएँ SELECT 1। दोनों ही मामलों में, 'विस्तारित' आउटपुट दिखाता है कि यह रूपांतरित हो गया था SELECT 1

इसी तरह, COUNT(*)में बदल जाता है COUNT(0)

नोट करने के लिए एक और बात: हाल के संस्करणों में अनुकूलन सुधार किए गए हैं। यह EXISTSबनाम विरोधी जोड़ की तुलना के लायक हो सकता है । आपका संस्करण एक बनाम दूसरे के साथ बेहतर काम कर सकता है।


4

कुछ डेटाबेस में यह अनुकूलन अभी तक काम नहीं करता है। उदाहरण के लिए PostgreSQL में उदाहरण के लिए संस्करण 9.6, यह विफल हो जाएगा।

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

और यह सफल होगा।

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT 1  -- This changed from the first query
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

यह विफल हो रहा है क्योंकि निम्नलिखित विफल रहता है लेकिन फिर भी इसका मतलब है कि एक अंतर है।

SELECT *
FROM ( VALUES (1),(1) ) AS t(x)
HAVING count(*) > 1;

आप इस विशेष क्विक के बारे में अधिक जानकारी प्राप्त कर सकते हैं और प्रश्न के मेरे उत्तर में युक्ति का उल्लंघन कर सकते हैं, क्या SQL कल्पना को EXISTS () में समूह BY की आवश्यकता है


एक दुर्लभ कोने का मामला, थोड़ा अजीब हो सकता है, लेकिन अभी तक फिर से, यह साबित करें कि डेटाबेस डिजाइन करते समय आपको बहुत सारे समझौते करने होंगे ...
jananolo

-1

मैंने हमेशा इस्तेमाल किया है select top 1 'x'(SQL Server)

सैद्धांतिक रूप से, select top 1 'x'अधिक कुशल होगा कि select *, जैसा कि पूर्व एक योग्य पंक्ति के अस्तित्व पर एक निरंतरता का चयन करने के बाद पूरा होगा, जबकि बाद वाला सब कुछ का चयन करेगा।

हालांकि, इस पर बहुत जल्दी प्रासंगिक हो सकता है, अनुकूलन ने संभवतः सभी प्रमुख RDBS में अंतर को अप्रासंगिक बना दिया है।


समझ में आता है। यही कारण है कि हो सकता है (या हो सकता है) बहुत कुछ मामलों में जहां से एक top nके बिना order byएक अच्छा विचार कर रहे हैं।
जोनलो

3
"सैद्धांतिक रूप से, ...." नहीं, सैद्धांतिक रूप select top 1 'x'से select *एक Existअभिव्यक्ति की तुलना में अधिक कुशल नहीं होना चाहिए । व्यावहारिक रूप से यह अधिक कुशल हो सकता है यदि ऑप्टिमाइज़र सबप्टिमल काम कर रहा है लेकिन सैद्धांतिक रूप से दोनों अभिव्यक्तियाँ समान हैं।
चमत्कारी १'३

-4

IF EXISTS(SELECT TOP(1) 1 FROMएक बेहतर आदत है लॉन्ग टर्म और प्लेटफ़ॉर्म पर क्योंकि आपको इस बात की चिंता करने की ज़रूरत नहीं है कि आपका वर्तमान प्लेटफ़ॉर्म / संस्करण कितना अच्छा या बुरा है; और SQL TOP nपैरामीटर करने योग्य की ओर बढ़ रहा है TOP(n)। यह एक सीखने योग्य कौशल होना चाहिए।


3
"प्लेटफ़ॉर्म के पार" से आपका क्या तात्पर्य है ? TOPSQL भी मान्य नहीं है।
ypercube y

"SQL बढ़ रहा है .." सादे गलत है। TOP (n)"क्वेरी" में कोई नहीं है - मानक क्वेरी भाषा। T-SQL पर एक है जो कि Microsoft SQL Server का उपयोग कर रही बोली है।
a_horse_with_no_name 20

मूल प्रश्न पर टैग "SQL सर्वर" है। लेकिन मैंने जो कहा, उसे नीचा दिखाना और विवाद करना ठीक है - इस साइट का उद्देश्य आसान डाउनवोटिंग को सक्षम करना है। मैं विस्तार से बोरिंग ध्यान के साथ आपकी परेड पर बारिश करने वाला कौन हूं?
अजेह
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.