गैर-सकल ARRAY () निर्माता की तुलना में array_agg () धीमा क्यों है?


14

मैं अभी कुछ पुराने कोड की समीक्षा कर रहा था, जो प्री-8.4 PostgreSQL के लिए लिखा गया था , और मैंने कुछ वास्तव में निफ्टी देखा। मुझे याद है कि एक कस्टम फंक्शन दिन में कुछ इस तरह से होता है, लेकिन मैं भूल गया कि पूर्व क्या array_agg()दिखता था। समीक्षा के लिए, आधुनिक एकत्रीकरण इस तरह लिखा जाता है।

SELECT array_agg(x ORDER BY x DESC) FROM foobar;

हालांकि, एक बार, यह इस तरह लिखा गया था,

SELECT ARRAY(SELECT x FROM foobar ORDER BY x DESC);

इसलिए, मैंने इसे कुछ परीक्षण आंकड़ों के साथ आजमाया।

CREATE TEMP TABLE foobar AS
SELECT * FROM generate_series(1,1e7)
  AS t(x);

परिणाम आश्चर्यजनक थे .. #OldSchoolCool तरीका बड़े पैमाने पर तेज था: एक 25% स्पीडअप। इसके अलावा, ORDER के बिना इसे सरल करते हुए, समान सुस्ती दिखाई गई।

# EXPLAIN ANALYZE SELECT ARRAY(SELECT x FROM foobar);
                                                         QUERY PLAN                                                          
-----------------------------------------------------------------------------------------------------------------------------
 Result  (cost=104425.28..104425.29 rows=1 width=0) (actual time=1665.948..1665.949 rows=1 loops=1)
   InitPlan 1 (returns $0)
     ->  Seq Scan on foobar  (cost=0.00..104425.28 rows=6017728 width=32) (actual time=0.032..716.793 rows=10000000 loops=1)
 Planning time: 0.068 ms
 Execution time: 1671.482 ms
(5 rows)

test=# EXPLAIN ANALYZE SELECT array_agg(x) FROM foobar;
                                                        QUERY PLAN                                                         
---------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=119469.60..119469.61 rows=1 width=32) (actual time=2155.154..2155.154 rows=1 loops=1)
   ->  Seq Scan on foobar  (cost=0.00..104425.28 rows=6017728 width=32) (actual time=0.031..717.831 rows=10000000 loops=1)
 Planning time: 0.054 ms
 Execution time: 2174.753 ms
(4 rows)

तो, यहाँ क्या हो रहा है। Array_agg , योजनाकार की SQL वूडू की तुलना में एक आंतरिक कार्य इतना धीमा क्यों है ?

X86_64 -pc-linux-gnu पर " PostgreSQL 9.5.5 का उपयोग करके , gcc द्वारा संकलित (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005, 64-बिट"

जवाबों:


17

एक ARRAY कंस्ट्रक्टर के बारे में "पुराना स्कूल" या "पुराना" कुछ भी नहीं है (यह वही ARRAY(SELECT x FROM foobar)है)। यह हमेशा की तरह आधुनिक है। सरल सरणी एकत्रीकरण के लिए इसका उपयोग करें।

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

एक उपशम के परिणामों से एक सरणी का निर्माण करना भी संभव है। इस रूप में, सरणी कंस्ट्रक्टर कुंजी शब्द के साथ लिखा जाता है जिसके ARRAYबाद एक कोष्ठक (कोष्ठक नहीं) उपवाक्य होता है।

समेकित फ़ंक्शनarray_agg() बहुमुखी में है कि यह एक में एकीकृत किया जा सकता है और अधिक SELECTसे अधिक कॉलम, एक ही में संभवतः अधिक एकत्रित साथ सूची SELECT, और मनमाने ढंग से समूहों के साथ गठित किया जा सकता GROUP BY। जबकि ARRAY कंस्ट्रक्टर केवल SELECTएक एकल कॉलम से लौटने वाले एकल सरणी को लौटा सकता है।

मैंने स्रोत कोड का अध्ययन नहीं किया, लेकिन यह स्पष्ट प्रतीत होता है कि बहुत अधिक बहुमुखी उपकरण भी अधिक महंगा है।

एक उल्लेखनीय अंतर: ARRAY कंस्ट्रक्टर खाली सरणी देता है ( {}) यदि कोई पंक्तियाँ योग्य नहीं हैं। उसी के लिए array_agg()लौटता है NULL


6

मेरा मानना ​​है कि इरविन द्वारा स्वीकृत उत्तर निम्नलिखित के साथ जोड़ा जा सकता है।

आमतौर पर, हम मूल प्रश्न के अनुसार, अस्थायी तालिकाओं (सूचकांकों के बिना) के साथ नियमित तालिकाओं के साथ काम कर रहे हैं। यह ध्यान रखना उपयोगी है कि एकत्रीकरण के दौरान एकत्रीकरण जैसे ARRAY_AGGमौजूदा सूचकांकों का लाभ नहीं उठाया जा सकता है

उदाहरण के लिए, निम्नलिखित प्रश्न मानें:

SELECT ARRAY(SELECT c FROM t ORDER BY id)

हम पर एक सूचकांक है, तो t(id, ...), सूचकांक एक अनुक्रमिक स्कैन के पक्ष में, इस्तेमाल किया जा सकता पर tपर एक प्रकार के द्वारा पीछा किया t.id। इसके अतिरिक्त, यदि एरे (यहाँ c) में लिपटे जा रहे आउटपुट कॉलम इंडेक्स का हिस्सा है (जैसे कि इंडेक्स ऑन t(id, c)या इंडेक्स ऑन इंडेक्स t(id) include(c)), तो यह भी इंडेक्स-ओनली स्कैन हो सकता है।

अब, निम्नलिखित के रूप में उस क्वेरी को फिर से लिखें:

SELECT ARRAY_AGG(c ORDER BY id) FROM t

अब, एकत्रीकरण सूचकांक का उपयोग नहीं करेगा और इसे मेमोरी में पंक्तियों को क्रमबद्ध करना होगा (या डिस्क पर बड़े डेटा सेटों के लिए और भी बदतर)। यह हमेशा एक क्रमिक स्कैन होगा tजिसके बाद एकत्रीकरण + छँटाई होगी

जहां तक ​​मुझे पता है, यह आधिकारिक दस्तावेज में प्रलेखित नहीं है, लेकिन स्रोत से प्राप्त किया जा सकता है। यह सभी वर्तमान संस्करणों के लिए मामला होना चाहिए, v11 शामिल हैं।


2
अच्छी बात। लेकिन सभी निष्पक्षता में, array_agg()या इसी तरह के समग्र कार्यों के साथ प्रश्न अभी भी अनुक्रमणिका जैसे उपकुंजी के साथ उत्तोलन कर सकते हैं SELECT ARRAY_AGG(c) FROM (SELECT c FROM t ORDER BY id) sub:। प्रति-कुल ORDER BYक्लाज वह है जो आपके उदाहरण में सूचकांक के उपयोग को रोकता है। एक सरणी निर्माणकर्ता तब से तेज है array_agg()जब या तो एक ही सूचकांक (या न ही) का उपयोग कर सकता है। यह उतना बहुमुखी नहीं है। देखें: dba.stackexchange.com/a/213724/3684
Erwin Brandstetter

1
सही, यह एक महत्वपूर्ण अंतर है। मैंने अपना जवाब थोड़ा स्पष्ट कर दिया कि यह टिप्पणी केवल तभी आयोजित होगी जब एकत्रीकरण समारोह को छाँटना होगा। आप वास्तव में अभी भी सरल मामले में सूचकांक से लाभ कमा सकते हैं, क्योंकि PostgreSQL कुछ गारंटी देता है कि एकत्रीकरण उसी क्रम में होगा जैसा कि उपकुंजी में परिभाषित किया गया है, जैसा कि लिंक में बताया गया है। वह काफी कूल है। मैं सोच रहा हूँ कि अगर यह अभी भी विभाजित टेबल और / या FDW टेबल और / या समानांतर श्रमिकों के मामले में है - और अगर PostgreSQL भविष्य के रिलीज में इस वादे को रख सकता है।
pbillen

रिकॉर्ड के लिए, मेरे पास स्वीकृत उत्तर पर संदेह करने का कोई मतलब नहीं था। मैंने केवल यह सोचा कि यह एकत्रीकरण के साथ संयोजन में अस्तित्व और सूचकांक के उपयोग के कारण के लिए एक अच्छा अतिरिक्त था।
pbillen

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