PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

SQL क्वेरी में (func ()).* सिंटैक्स के साथ एकाधिक फ़ंक्शन evals से कैसे बचें?

आप इसे एक सबक्वायरी में लपेट सकते हैं लेकिन यह OFFSET 0 के बिना सुरक्षित होने की गारंटी नहीं है हैक। 9.3 में, LATERAL . का उपयोग करें . समस्या पार्सर द्वारा प्रभावी रूप से मैक्रो-विस्तार * . के कारण होती है एक कॉलम सूची में।

समाधान

कहां:

SELECT (my_func(x)).* FROM some_table;

my_func evaluate का मूल्यांकन करेगा n n . के लिए समय फ़ंक्शन से परिणाम कॉलम, यह सूत्रीकरण:

SELECT (mf).* FROM (
    SELECT my_func(x) AS mf FROM some_table
) sub;

आम तौर पर नहीं होगा, और रनटाइम पर एक अतिरिक्त स्कैन जोड़ने के लिए नहीं जाता है। यह सुनिश्चित करने के लिए कि एकाधिक मूल्यांकन नहीं किया जाएगा, आप OFFSET 0 . का उपयोग कर सकते हैं CTE की सीमाओं को ऑप्टिमाइज़ करने में PostgreSQL की विफलता को हैक या दुरुपयोग करें:

SELECT (mf).* FROM (
    SELECT my_func(x) AS mf FROM some_table OFFSET 0
) sub;

या:

WITH tmp(mf) AS (
    SELECT my_func(x) FROM some_table
)
SELECT (mf).* FROM tmp;

PostgreSQL 9.3 में आप LATERAL . का उपयोग कर सकते हैं एक स्वस्थ व्यवहार पाने के लिए:

SELECT mf.*
FROM some_table
LEFT JOIN LATERAL my_func(some_table.x) AS mf ON true;

LEFT JOIN LATERAL ... ON true मूल क्वेरी की तरह सभी पंक्तियों को बरकरार रखता है, भले ही फ़ंक्शन कॉल कोई पंक्ति न लौटाए।

डेमो

एक ऐसा फ़ंक्शन बनाएं जो प्रदर्शन के रूप में इनलाइन करने योग्य न हो:

CREATE OR REPLACE FUNCTION my_func(integer)
RETURNS TABLE(a integer, b integer, c integer) AS $$
BEGIN
    RAISE NOTICE 'my_func(%)',$1;
    RETURN QUERY SELECT $1, $1, $1;
END;
$$ LANGUAGE plpgsql;

और डमी डेटा की एक तालिका:

CREATE TABLE some_table AS SELECT x FROM generate_series(1,10) x;

फिर उपरोक्त संस्करणों का प्रयास करें। आप देखेंगे कि पहला प्रति आमंत्रण तीन नोटिस उठाता है; बाद वाला केवल एक ही उठाता है।

क्यों?

अच्छा प्रश्न। यह भयानक है।

ऐसा लगता है:

(func(x)).*

के रूप में विस्तारित किया गया है:

(my_func(x)).i, (func(x)).j, (func(x)).k, (func(x)).l

पार्सिंग में, debug_print_parse . पर एक नज़र के अनुसार , debug_print_rewritten और debug_print_plan . (छंटनी) पार्स ट्री इस तरह दिखता है:

   :targetList (
      {TARGETENTRY 
      :expr 
         {FIELDSELECT 
         :arg 
            {FUNCEXPR 
            :funcid 57168 
                 ...
            }
         :fieldnum 1 
         :resulttype 23 
         :resulttypmod -1 
         :resultcollid 0
         }
      :resno 1 
      :resname i 
       ...
      }
      {TARGETENTRY 
      :expr 
         {FIELDSELECT 
         :arg 
            {FUNCEXPR 
            :funcid 57168 
                 ...
            }
         :fieldnum 2 
         :resulttype 20 
         :resulttypmod -1 
         :resultcollid 0
         }
      :resno 2 
      :resname j 
       ...
      }
      {TARGETENTRY 
      :expr 
         {FIELDSELECT 
         :arg 
            {FUNCEXPR 
            :funcid 57168 
             ...
            }
         :fieldnum 3 
         :...
         }
      :resno 3 
      :resname k 
       ...
      }
      {TARGETENTRY 
      :expr 
         {FIELDSELECT 
         :arg 
            {FUNCEXPR 
            :funcid 57168 
             ...
            }
         :fieldnum 4 
          ...
         }
      :resno 4 
      :resname l 
       ...
      }
   )

इसलिए मूल रूप से, हम नोड्स को क्लोन करके वाइल्डकार्ड का विस्तार करने के लिए एक डंब पार्सर हैक का उपयोग कर रहे हैं।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. डेटटाइम ऑब्जेक्ट पर अलग-अलग टाइमज़ोन_टाइप्स

  2. ग्रह संरेखण

  3. रेल प्रवासन:PostgreSQL पर Bigint विफल हो रहा है?

  4. क्या समाप्ति समय निर्धारित करने का कोई तरीका है, जिसके बाद PostgreSQL में डेटा प्रविष्टि स्वचालित रूप से हटा दी जाती है?

  5. PostgreSQL (psql) में सभी डेटाबेस का आकार प्राप्त करें