LATERAL और PostgreSQL में एक उपश्रेणी के बीच अंतर क्या है?


147

चूंकि Postgres करने की क्षमता के साथ बाहर आया था LATERAL , इसलिए मैं इसे पढ़ रहा हूं, क्योंकि मैं वर्तमान में अपनी टीम के लिए जटिल डेटा डंप करता हूं जिसमें बहुत सारी अकुशल उपकथाएं हैं जो समग्र क्वेरी को चार मिनट या उससे अधिक समय लेती हैं।

मैं समझता हूं कि LATERALजॉइन मेरी मदद करने में सक्षम हो सकते हैं, लेकिन इस तरह के लेख पढ़ने के बाद भी हीप एनालिटिक्स के , मैं अभी भी काफी अनुसरण नहीं करता हूं।

LATERALज्वाइन के लिए उपयोग का मामला क्या है ? LATERALज्वाइन और सबक्वेरी में क्या अंतर है ?


2
blog.heapanalytics.com/… और explainextended.com/2009/07/16/inner-join-vs-cross-apply (SQL सर्वर SQL मानक से applyसमान है lateral)
a_horse_ith_no_name

जवाबों:


163

एक सहसंबद्ध उपशम की तरह

एक LATERALजॉइन (पोस्टग्रैजेस 9.3 या बाद का) एक सहसंबद्ध सबक्वेरी की तरह अधिक है , न कि एक सादी उपश्रेणी। जैसे कि ओन्डोमर ने बताया , किसी कार्य में LATERALशामिल होने के अधिकार के लिए एक फ़ंक्शन या सबक्वेरी का मूल्यांकन उसके बाईं ओर की प्रत्येक पंक्ति के लिए एक बार किया जाना चाहिए - ठीक एक सहसंबंधित उप-वर्ग की तरह - जबकि एक सादे उप-तालिका (टेबल एक्सप्रेशन) का मूल्यांकन केवल एक बार किया जाता है। (क्वेरी प्लानर के पास हालांकि, प्रदर्शन के अनुकूलन के तरीके हैं।)
इस संबंधित उत्तर में दोनों पक्षों के लिए कोड उदाहरण हैं, एक ही समाधान हल करना:

एक से अधिक कॉलम वापस करने के लिए , एक LATERALजॉइन आमतौर पर सरल, क्लीनर और तेज होता है।
इसके अलावा, याद रखें कि एक सहसंबद्ध उपशम के बराबर हैLEFT JOIN LATERAL ... ON true :

मैनुअल पर पढ़ें LATERAL

यह उन चीज़ों से अधिक आधिकारिक है, जिन्हें हम यहां जवाब देने जा रहे हैं:

चीजें एक सबक्वेरी नहीं कर सकती हैं

वहाँ रहे हैं चीजें हैं जो एक LATERALमें शामिल होने के लिए कर सकते हैं, लेकिन एक (सहसंबद्ध) सबक्वेरी (आसानी से) नहीं कर सकता। एक संबद्ध उपकुंजी केवल एक मान लौटा सकती है, न कि कई कॉलम और न ही कई पंक्तियाँ - नंगे फ़ंक्शन कॉल के अपवाद के साथ (जो पंक्तियों को कई पंक्तियों को वापस करने पर गुणा करें)। लेकिन यहां तक ​​कि निश्चित सेट even रिटर्निंग फ़ंक्शन केवल FROMक्लॉज में अनुमति दी जाती है । जैसा unnest()Postgres 9.4 या बाद में कई मानकों के साथ। नियम पुस्तिका:

यह केवल FROMखंड में अनुमति है ;

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

CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

खंड ,में अल्पविराम ( ) के लिए FROMसंक्षिप्त संकेतन है CROSS JOIN
LATERALस्वचालित रूप से तालिका कार्यों के लिए मान लिया गया है।
के विशेष मामले के बारे में अधिक UNNEST( array_expression [, ... ] ):

SELECTसूची में सेट-रिटर्निंग फ़ंक्शन

आप सीधे सूची unnest()में सेट-रिटर्न फ़ंक्शन का उपयोग कर सकते SELECTहैं। यह SELECT9.6 पोस्ट करने के लिए एक ही सूची में एक से अधिक ऐसे समारोह के साथ आश्चर्यजनक व्यवहार का प्रदर्शन करता था । लेकिन अंत में इसे पोस्टग्रेज 10 के साथ पवित्रा किया गया है और अब एक वैध विकल्प है (भले ही मानक एसक्यूएल नहीं)। देख:

उपरोक्त उदाहरण पर निर्माण:

SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

तुलना:

dgfield pg के लिए 9.6 यहाँ
pg 10 के लिए dbfiddle यहाँ

गलत सूचना को स्पष्ट करें

नियम पुस्तिका:

के लिए INNERऔर OUTERशामिल होने के प्रकार, एक में शामिल होने के शर्त अवश्य, अर्थात् वास्तव में से एक NATURAL, ON join_condition , या USING( join_column [...])। अर्थ के लिए नीचे देखें।
के लिए CROSS JOIN, इनमें से कोई भी क्लॉज़ दिखाई नहीं दे सकता है।

तो ये दोनों प्रश्न मान्य हैं (भले ही विशेष रूप से उपयोगी न हों):

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

जबकि यह एक नहीं है:

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

क्यों ऐसा इसलिए है @ Andomar के कोड उदाहरण सही है ( CROSS JOINएक शर्त में शामिल होने की आवश्यकता नहीं है) और @ अट्टिला की है अवैध था।


वहाँ कुछ चीजें हैं जो एक सबक्वेरी एक लेटरल जॉइन नहीं कर सकती हैं। खिड़की के कार्यों की तरह। यहाँ के रूप में
इवान कैरोल

@ EvanCarroll: मुझे लिंक में कोई सहसंबद्ध उपश्रेणी नहीं मिली। लेकिन मैंने एक और जवाब दिया कि एक उपसमुच्चय में एक विंडो फ़ंक्शन प्रदर्शित करने के लिए LATERAL: gis.stackexchange.com/a/230070/7244
Erwin Brandstetter

1
क्लीनर और तेज? कुछ मामलों में तेजी से परिमाण की तरह। मेरे पास एक क्वेरी थी जो LATERAL पर स्विच करने के बाद दिनों से सेकंड तक चली गई थी।
रोवीको

52

एक गैर lateralऔर एक सम्मिलित के बीच का अंतर lateralयह है कि क्या आप बाएं हाथ की मेज की पंक्ति को देख सकते हैं। उदाहरण के लिए:

select  *
from    table1 t1
cross join lateral
        (
        select  *
        from    t2
        where   t1.col1 = t2.col1 -- Only allowed because of lateral
        ) sub

इस "आउटवर्ड लुकिंग" का अर्थ है कि उपकुंजी का एक से अधिक बार मूल्यांकन किया जाना है। आखिरकार, t1.col1कई मूल्यों को मान सकते हैं।

इसके विपरीत, एक गैर में lateralशामिल होने के बाद उपशम का मूल्यांकन एक बार किया जा सकता है:

select  *
from    table1 t1
cross join
        (
        select  *
        from    t2
        where   t2.col1 = 42 -- No reference to outer query
        ) sub

जैसा कि आवश्यक है lateral, आंतरिक क्वेरी बाहरी क्वेरी पर किसी भी तरह से निर्भर नहीं करती है। एक lateralक्वेरी एक का एक उदाहरण है correlatedक्वेरी ही बाहर पंक्तियों के साथ अपने संबंध की वजह से, क्वेरी।


5
यह पार्श्व जुड़ाव की सबसे साफ व्याख्या है।
अवधी

स्पष्टीकरण को समझना आसान है, धन्यवाद।
२०:४२ पर अरिलवान

कैसे select * from table1 left join t2 using (col1)तुलना करता है ? यह मेरे लिए अस्पष्ट है जब एक जॉइनिंग / ऑन कंडीशन अपर्याप्त है और यह पार्श्व उपयोग करने के लिए अधिक समझ में आता है।
No_name

9

सबसे पहले, लेटरल और क्रॉस लागू एक ही बात है । इसलिए आप Cross Apply के बारे में भी पढ़ सकते हैं। चूंकि यह SQL सर्वर में उम्र के लिए लागू किया गया था, इसलिए आपको इसके बारे में अधिक जानकारी मिल जाएगी।

दूसरा, मेरी समझ के अनुसार , ऐसा कुछ भी नहीं है जिसे आप पार्श्व का उपयोग करने के बजाय सबक्वेरी का उपयोग नहीं कर सकते। परंतु:

निम्नलिखित प्रश्न पर विचार करें।

Select A.*
, (Select B.Column1 from B where B.Fk1 = A.PK and Limit 1)
, (Select B.Column2 from B where B.Fk1 = A.PK and Limit 1)
FROM A 

आप इस स्थिति में पार्श्व का उपयोग कर सकते हैं।

Select A.*
, x.Column1
, x.Column2
FROM A LEFT JOIN LATERAL (
  Select B.Column1,B.Column2,B.Fk1 from B  Limit 1
) x ON X.Fk1 = A.PK

इस क्‍वेरी में आप सीमित क्‍लॉज के कारण सामान्‍य जुड़ाव का उपयोग नहीं कर सकते हैं। लेटरल या क्रॉस अप्लाई का इस्तेमाल किया जा सकता हैसाधारण ज्वाइन कंडीशन नहीं होने पर है

लेटरल या क्रॉस अप्लाई के लिए अधिक उपयोग हैं, लेकिन यह सबसे आम है जो मुझे मिला।


1
वास्तव में, मुझे आश्चर्य है कि PostgreSQL lateralइसके बजाय क्यों उपयोग करता है apply। शायद Microsoft ने सिंटैक्स का पेटेंट कराया है?
एंडोमर

9
@Andomar AFAIK lateralSQL मानक में है, लेकिन applyनहीं है।
म्यू बहुत छोटा है

LEFT JOINएक सम्मिलित हालत की आवश्यकता है। इसे ON TRUEतब तक करें जब तक आप किसी तरह प्रतिबंधित नहीं करना चाहते।
एरविन ब्रान्डेसटेटर

इरविन सही है, आपको तब तक एक त्रुटि मिलेगी जब तक कि आप cross joinया एक onशर्त का उपयोग नहीं करते हैं
एंडोमर

1
@Andomar: इस गलत सूचना के कारण मैंने स्पष्ट करने के लिए एक और उत्तर जोड़ा।
एरविन ब्रान्डस्टैटर

4

एक बात जिस पर किसी ने ध्यान नहीं दिया है वह यह है कि आप LATERALप्रत्येक चयनित पंक्ति पर उपयोगकर्ता-परिभाषित फ़ंक्शन को लागू करने के लिए क्वेरीज़ का उपयोग कर सकते हैं ।

उदाहरण के लिए:

CREATE OR REPLACE FUNCTION delete_company(companyId varchar(255))
RETURNS void AS $$
    BEGIN
        DELETE FROM company_settings WHERE "company_id"=company_id;
        DELETE FROM users WHERE "company_id"=companyId;
        DELETE FROM companies WHERE id=companyId;
    END; 
$$ LANGUAGE plpgsql;

SELECT * FROM (
    SELECT id, name, created_at FROM companies WHERE created_at < '2018-01-01'
) c, LATERAL delete_company(c.id);

यही कारण है कि मुझे पता है कि इस तरह की चीज़ को PostgreSQL में कैसे करना है।

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