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

PostgreSQL विंडो फ़ंक्शन:तुलना द्वारा विभाजन

कई अलग-अलग विंडो फ़ंक्शंस और दो सबक्वेरी का उपयोग करते हुए, यह शालीनता से तेजी से काम करना चाहिए:

WITH events(id, event, ts) AS (
  VALUES
   (1, 12, '2014-03-19 08:00:00'::timestamp)
  ,(2, 12, '2014-03-19 08:30:00')
  ,(3, 13, '2014-03-19 09:00:00')
  ,(4, 13, '2014-03-19 09:30:00')
  ,(5, 12, '2014-03-19 10:00:00')
   )
SELECT first_value(pre_id)  OVER (PARTITION BY grp ORDER BY ts)      AS pre_id
     , id, ts
     , first_value(post_id) OVER (PARTITION BY grp ORDER BY ts DESC) AS post_id
FROM  (
   SELECT *, count(step) OVER w AS grp
   FROM  (
      SELECT id, ts
           , NULLIF(lag(event) OVER w, event) AS step
           , lag(id)  OVER w AS pre_id
           , lead(id) OVER w AS post_id
      FROM   events
      WINDOW w AS (ORDER BY ts)
      ) sub1
   WINDOW w AS (ORDER BY ts)
   ) sub2
ORDER  BY ts;

ts . का उपयोग करना टाइमस्टैम्प कॉलम के नाम के रूप में।
मान लें कि ts अद्वितीय होना - और अनुक्रमित (एक अद्वितीय बाधा स्वचालित रूप से ऐसा करती है)।

50k पंक्तियों वाली वास्तविक जीवन तालिका वाले परीक्षण में इसे केवल एक एकल अनुक्रमणिका स्कैन . की आवश्यकता होती है . तो, बड़ी टेबल के साथ भी शालीनता से तेज होना चाहिए। इसकी तुलना में, शामिल / विशिष्ट के साथ आपकी क्वेरी एक मिनट (उम्मीद के अनुसार) के बाद समाप्त नहीं हुई।
यहां तक ​​​​कि एक अनुकूलित संस्करण, एक समय में एक क्रॉस जॉइन से निपटना (बायां जुड़ाव मुश्किल से सीमित स्थिति के साथ प्रभावी रूप से सीमित है क्रॉस जॉइन) एक मिनट के बाद समाप्त नहीं हुआ।

बड़ी तालिका के साथ सर्वश्रेष्ठ प्रदर्शन के लिए, विशेष रूप से work_mem के लिए अपनी मेमोरी सेटिंग्स को ट्यून करें। (बड़े प्रकार के संचालन के लिए)। अपने सत्र के लिए अस्थायी रूप से इसे (बहुत) उच्चतर सेट करने पर विचार करें यदि आप रैम को छोड़ सकते हैं। यहां और यहां और पढ़ें।

कैसे?

  1. सबक्वेरी में sub1 घटना को पिछली पंक्ति से देखें और इसे केवल तभी रखें जब यह बदल गया हो, इस प्रकार एक नए समूह के पहले तत्व को चिह्नित करना। साथ ही, id प्राप्त करें पिछली और अगली पंक्ति की (pre_id , post_id )।

  2. सबक्वेरी में sub2 , count() केवल गैर-शून्य मानों की गणना करता है। परिणामी grp लगातार समान घटनाओं के ब्लॉक में साथियों को चिह्नित करता है।

  3. फाइनल में SELECT , पहला pre_id लें और अंतिम post_id वांछित परिणाम पर पहुंचने के लिए प्रत्येक पंक्ति के लिए प्रति समूह।
    वास्तव में, यह बाहरी SELECT में और भी तेज़ होना चाहिए :

     last_value(post_id) OVER (PARTITION BY grp ORDER BY ts
                               RANGE BETWEEN UNBOUNDED PRECEDING
                                     AND     UNBOUNDED FOLLOWING) AS post_id
    

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

एसक्यूएल फिडल.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. क्या किसी जॉइन में टेबल का क्रम मायने रखता है, जब LEFT (बाहरी) जॉइन का उपयोग किया जाता है?

  2. स्वत:पूर्ण फ़ील्ड के लिए समान UTF-8 स्ट्रिंग्स

  3. कुप्पी-sqlalchemy के साथ स्वत:वृद्धिशील प्राथमिक कुंजी बनाने में असमर्थ

  4. पोस्टग्रेज पासवर्ड प्रमाणीकरण विफल रहता है

  5. कठपुतली के साथ PostgreSQL परिनियोजन और कॉन्फ़िगरेशन