इनलाइन दृश्य और खंड के बीच अंतर?


9

इनलाइन विचार आपको एक उप-वर्ग से चुनने की अनुमति देते हैं जैसे कि यह एक अलग तालिका थी:

SELECT
    *
FROM /* Selecting from a query instead of table */
    (
        SELECT
            c1
        FROM
            t1
        WHERE
            c1 > 0
    ) a
WHERE
    a.c1 < 50;

मैंने इसे विभिन्न शब्दों का उपयोग करते हुए देखा है: इनलाइन विचार, क्लॉज, सीटीई और व्युत्पन्न तालिकाओं के साथ। मुझे लगता है कि वे एक ही चीज़ के लिए अलग-अलग विक्रेता विशिष्ट वाक्यविन्यास हैं।

क्या यह गलत धारणा है? क्या इन दोनों के बीच कोई तकनीकी / प्रदर्शन अंतर हैं?


5
स्टैंडर्ड एसक्यूएल से "आधिकारिक" नाम व्युत्पन्न तालिका (जो ओरेकल नाम इनलाइन व्यू ) और सामान्य तालिका अभिव्यक्ति (= WITH...) हैं। आप एक CTE के रूप में हर व्युत्पन्न तालिका को फिर से लिख सकते हैं, लेकिन शायद दूसरा तरीका राउंड (उदाहरण के लिए CTE या CTE का कई बार उपयोग करना)
dnoeth

जवाबों:


8

इनलाइन विचारों (व्युत्पन्न टेबल) और Oracle में क्लॉज (CTE) के बीच कुछ महत्वपूर्ण अंतर हैं। उनमें से कुछ काफी सार्वभौमिक हैं, अर्थात अन्य RDBMS पर लागू होते हैं।

  1. WITH पुनरावर्ती उपकेंद्रों का निर्माण करने के लिए इस्तेमाल किया जा सकता है, इनलाइन व्यू-नोट (जहां तक ​​मुझे पता है कि सभी RDBMS के लिए है जो CTE का समर्थन करते हैं)
  2. WITHक्लॉज में उपश्रेणी अधिक शारीरिक रूप से पहले निष्पादित होने की संभावना है; कई मामलों में, WITHअलग-अलग निष्पादन योजनाओं का चयन करने के लिए ऑप्टिमाइज़र के बीच चयन करने से ऑप्टिमाइज़र बनता है (मुझे लगता है कि यह विशिष्ट विक्रेता है, शायद संस्करण भी विशिष्ट है)।
  3. सबक्वेरी WITHको एक अस्थायी तालिका के रूप में उत्प्रेरित किया जा सकता है (यदि कोई अन्य विक्रेता लेकिन ओरेकल इस सुविधा का समर्थन करता है तो मुझे पता नहीं है)।
  4. सबक्वेरी को WITHकई बार, अन्य उप-श्रेणियों में, और मुख्य क्वेरी में (अधिकांश RDBMS के लिए सही) संदर्भित किया जा सकता है।

MySQL (कम से कम नवीनतम MariaDB संस्करण) व्युत्पन्न टेबल (और यहां तक ​​कि इंडेक्स भी जोड़ सकते हैं) को मटेरियल कर सकते हैं।
ypercube y

3
मैं जोड़ना चाहूंगा कि, CTE के उपयोग से साइड इफ़ेक्ट के रूप में, सामान्यतः मनुष्यों के लिए अधिक पठनीय है।
जोशी बोडियो

@JoishiBodio: व्यक्तिगत रूप से, मैं आपसे सहमत हूं, लेकिन पठनीयता काफी व्यक्तिपरक मामला है। मैं इसके उल्लेख से बचना चाहता हूँ
a1ex07

इसके अलावा, एक सीटीई पहले से घोषित सीटीई का संदर्भ दे सकता है। एक व्युत्पन्न तालिका उसी स्तर पर पहले से घोषित तालिका का संदर्भ नहीं दे सकती है जब तक कि LATERALउसका उपयोग नहीं किया जाता है।
लेनार्ट

8

अन्य उत्तर सिंटैक्स मतभेदों को अच्छी तरह से कवर करते हैं इसलिए मैं इसमें नहीं जाऊंगा। इसके बजाय यह उत्तर ओरेकल में प्रदर्शन को कवर करेगा।

Oracle ऑप्टिमाइज़र CTE के परिणामों को आंतरिक अस्थायी तालिका में सूचीबद्ध करने का विकल्प चुन सकता है। यह लागत-आधारित अनुकूलन के बजाय ऐसा करने के लिए एक अनुमानी का उपयोग करता है। ह्यूरिस्टिक कुछ ऐसा है जैसे "सीटीई को स्थिर करें यदि यह एक तुच्छ अभिव्यक्ति नहीं है और सीटीई को क्वेरी में एक से अधिक बार संदर्भित किया जाता है"। कुछ प्रश्न हैं जिनके लिए सामग्रीकरण प्रदर्शन में सुधार करेगा। कुछ प्रश्न हैं जिनके लिए सामग्रीकरण नाटकीय रूप से प्रदर्शन को नीचा दिखाएगा। निम्नलिखित उदाहरण थोड़ा सा वंचित है, लेकिन यह बिंदु को अच्छी तरह दिखाता है:

पहले एक प्राथमिक कुंजी के साथ एक तालिका बनाएं जिसमें 1 से 10000 तक पूर्णांक हैं:

CREATE TABLE N_10000 (NUM_ID INTEGER NOT NULL, PRIMARY KEY (NUM_ID));

INSERT /*+APPEND */ INTO N_10000
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 10000
ORDER BY LEVEL;

COMMIT;

निम्न क्वेरी पर विचार करें जो दो व्युत्पन्न तालिकाओं का उपयोग करती है:

SELECT t1.NUM_ID
FROM 
(
  SELECT n1.NUM_ID
  FROM N_10000 n1
  CROSS JOIN N_10000 n2
) t1
LEFT OUTER JOIN 
(
  SELECT n1.NUM_ID
  FROM N_10000 n1
  CROSS JOIN N_10000 n2
) t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;

हम इस क्वेरी को देख सकते हैं और जल्दी से निर्धारित कर सकते हैं कि यह किसी भी पंक्तियों को वापस नहीं करेगा। ओरेकल को यह निर्धारित करने के लिए इंडेक्स का उपयोग करने में सक्षम होना चाहिए। मेरी मशीन पर क्वेरी निम्न योजना के साथ लगभग तुरंत समाप्त होती है:

अच्छी योजना

मुझे खुद को दोहराना पसंद नहीं है, इसलिए चलिए CTE के साथ एक ही क्वेरी की कोशिश करते हैं:

WITH N_10000_CTE AS (
  SELECT n1.NUM_ID
  FROM N_10000 n1
  CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;

यहाँ योजना है:

बुरी योजना

यह वास्तव में एक बुरी योजना है। इंडेक्स का उपयोग करने के बजाय, ओरेकल 10000 X 10000 = 100000000 पंक्तियों को एक अस्थायी तालिका में केवल 0 पंक्तियों को वापस करने के लिए उत्प्रेरित करता है। इस योजना की लागत लगभग 6 M है जो अन्य क्वेरी की तुलना में बहुत अधिक है। क्वेरी को मेरी मशीन पर समाप्त होने में 68 सेकंड लगे।

ध्यान दें कि यदि अस्थायी तालिकाओं में पर्याप्त मेमोरी या खाली स्थान नहीं है तो क्वेरी विफल हो सकती है।

मैं INLINECTE को उत्प्रेरित करने से ऑप्टिमाइज़र को हटाने के लिए अनिर्धारित संकेत का उपयोग कर सकता हूं :

WITH N_10000_CTE AS (
  SELECT /*+ INLINE */ n1.NUM_ID
  FROM N_10000 n1
  CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;

वह क्वेरी इंडेक्स का उपयोग करने में सक्षम है और लगभग तुरंत खत्म कर देता है। क्वेरी की लागत पहले की तरह 11. है, इसलिए दूसरी क्वेरी के लिए, ओरेकल द्वारा उपयोग किए जाने वाले हेयुरिस्टिक ने इसका परिणाम दिया, जिसमें क्वेरी की बजाय 11 की अनुमानित लागत के साथ 6 एम की अनुमानित लागत के साथ एक क्वेरी चुना गया था।


1

SQL सर्वर के लिए, WITH CTEअस्थायी नाम परिणाम सेट निर्दिष्ट करता है, लेकिन केवल पहले के लिए आवश्यक है CTE। अर्थात

WITH CTE AS (SELECT .... FROM), 
CTE2 AS (SELECT .... FROM)

SELECT CTE.Column, CTE2.Column
FROM CTE
INNER JOIN CTE2 on CTE.Column = CTE2.Column

लेकिन यह एक उपश्रेणी नहीं है, या सहसंबंधी उपश्रेणी। ऐसी चीजें हैं जो आप सीटीई के साथ कर सकते हैं जो आप एसक्यूएल सर्वर में एक उप-क्वेरी के साथ नहीं कर सकते हैं, जैसे कि सीटीई में संदर्भित तालिकाओं को अपडेट करें। यहां सीटीई के साथ एक तालिका को अद्यतन करने का एक उदाहरण है।

एक उपशम कुछ ऐसा होगा

SELECT
   C1,
   (SELECT C2 FROM SomeTable) as C2
FROM Table

या एक सह-संबद्ध उप-क्वेरी वह है जो आपने अपने ओपी में प्रदान की है यदि आप a.c1 के आधार पर अपने परिणामों को संदर्भित / शामिल / सीमित करते हैं।

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


1

withOracle में क्लॉज और एक उपश्रेणी के बीच मुख्य अंतर यह है कि आप क्लॉज़ के भीतर एक क्वेरी को कई बार संदर्भित कर सकते हैं। आप इसके साथ कुछ अनुकूलन कर सकते हैं जैसे कि इसे materializeसंकेत का उपयोग करके एक अस्थायी तालिका में बदलना । आप इसे एक withखंड के अंदर संदर्भित करके इसके साथ पुनरावर्ती प्रश्न भी कर सकते हैं । आप इनलाइन दृश्य के साथ ऐसा नहीं कर सकते।

अधिक जानकारी यहाँ और यहाँ मिल सकती है


सामान्य भौतिक में संकेत की आवश्यकता नहीं है। डिफ़ॉल्ट रूप से ओरेकल ऑप्टिमाइज़र यह तय करता है कि सीटीई को उत्प्रेरित करने का कोई मतलब है या नहीं - लेकिन आप संकेत के साथ ऑप्टिमाइज़र मूल्यांकन को अधिलेखित कर सकते हैं MATERIALIZEINLINEविपरीत के लिए।
वर्नफ्रीड डमशेकिट

@ErnfriedDomscheit जो सच है। लेकिन कभी-कभी ऑप्टिमाइज़र सीटीई को उत्प्रेरित करने का चयन नहीं करता है और उस स्थिति में, materializeसंकेत का उपयोग करना वैध विकल्प है। मुझे कभी-कभी इसे निर्दिष्ट करने की आवश्यकता होती है जब मैं बहुत जटिल प्रश्नों का अनुकूलन करता था जहां मुझे पता था कि सीटीई को अमल में लाने से निष्पादन योजना को फायदा होगा।
मार्को वोडोपिजा

0

आपको CTE के SQL सर्वर के साथ न केवल सावधानी बरतने की ज़रूरत है, ऐसे मामले भी हैं जहाँ CTE सबक्वेरी, क्रॉस अप्लाई, इत्यादि की तुलना में CTE का उपयोग करते समय प्रश्न बहुत खराब करते हैं।

हमेशा की तरह विभिन्न लोड शर्तों के तहत किसी भी क्वेरी का परीक्षण करना महत्वपूर्ण है यह निर्धारित करने के लिए कि कौन सबसे अच्छा काम करता है।

ऑरेकल के साथ @scsimon के समान, कभी-कभी MS SQL सर्वर इंडेक्स के उपयोग के संबंध में वह नहीं करता है जो आप अपेक्षा करते हैं।

यदि आप एक ही डेटा का एक से अधिक बार उपयोग करने जा रहे हैं, तो सीटीई का उपयोग अधिक उपयोगी हो सकता है, यदि आप केवल एक बार इसका उपयोग कर रहे हैं, तो अक्सर बड़े डेटासेट में एक सबक्वेरी तेज होती है।

उदाहरण के लिए * (मेरे उपसमुच्चय) में से कुछ का चयन करें ...

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