मैं एक पुनरावर्ती CTE की कार्डिनैलिटी को 'संकेत' कैसे दे सकता हूं?


10

मैं निम्नलिखित पुनरावर्ती CTE का उपयोग एक न्यूनतम उदाहरण के रूप में कर रहा हूं, लेकिन सामान्य तौर पर, ऑप्टिमाइज़र को पुनरावर्ती CTE के लिए डिफ़ॉल्ट 'अनुमानित' कार्डिनैलिटी का उपयोग करना पड़ता है:

with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * from w;
/*
 n
---
 1
 2
 3
 4
 5
*/

explain analyze
with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * from w;
/*
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 CTE Scan on w  (cost=2.95..3.57 rows=31 width=4) (actual time=0.005..0.020 rows=5 loops=1)
   CTE w
     ->  Recursive Union  (cost=0.00..2.95 rows=31 width=4) (actual time=0.003..0.017 rows=5 loops=1)
           ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
           ->  WorkTable Scan on w w_1  (cost=0.00..0.23 rows=3 width=4) (actual time=0.002..0.002 rows=1 loops=5)
                 Filter: (n < 5)
                 Rows Removed by Filter: 0
*/

उपरोक्त योजना में rows=31अनुमानित और rows=5वास्तविक कार्डिनैलिटी पर ध्यान दें । कुछ मामलों में 100 को अनुमान के रूप में उपयोग किया जा रहा है, मुझे अनुमानों के पीछे सटीक तर्क यकीन नहीं है।

मेरी वास्तविक दुनिया की समस्या में, खराब कार्डिनिटी का अनुमान एक तेज 'नेस्टेड लूप्स' योजना को चुने जाने से रोक रहा है। मैं एक पुनरावर्ती CTE के लिए यह काम करने के लिए ऑप्टिमाइज़र कार्डिनैलिटी को 'संकेत' कैसे दे सकता हूं?


5
यह कई मामलों में से एक है, जहां आँकड़े संकेत वास्तव में अच्छा होगा। नहीं है COSTकार्यों पर है, लेकिन बहुत ज्यादा नहीं बाकी। मैं इसे pgsql- हैकर्स पर बढ़ाने का सुझाव देता हूं, लेकिन आप "संकेत" बहस के n'th पुनरावृत्ति में फंस जाएंगे, गर्म हवा के द्रव्यमान को बर्बाद कर रहे हैं और कुछ भी हासिल नहीं करेंगे :-(
क्रेग रिंगर

जवाबों:


8

मैंने इस तरह से इस मुद्दे पर काम किया है, लेकिन मैं उम्मीद कर रहा हूँ कि कम मज़ेदार तरीका है:

explain analyze
with recursive w(n) as ( select 1 union all select n+1 from w where n<5 )
select * from w limit (select count(*) from w);
/*
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Limit  (cost=3.66..3.72 rows=3 width=4) (actual time=0.032..0.034 rows=5 loops=1)
   CTE w
     ->  Recursive Union  (cost=0.00..2.95 rows=31 width=4) (actual time=0.003..0.019 rows=5 loops=1)
           ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=1 loops=1)
           ->  WorkTable Scan on w w_1  (cost=0.00..0.23 rows=3 width=4) (actual time=0.002..0.002 rows=1 loops=5)
                 Filter: (n < 5)
                 Rows Removed by Filter: 0
   InitPlan 2 (returns $2)
     ->  Aggregate  (cost=0.70..0.71 rows=1 width=0) (actual time=0.029..0.030 rows=1 loops=1)
           ->  CTE Scan on w w_2  (cost=0.00..0.62 rows=31 width=0) (actual time=0.005..0.025 rows=5 loops=1)
   ->  CTE Scan on w  (cost=0.00..0.62 rows=31 width=4) (actual time=0.000..0.002 rows=5 loops=1)
*/
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.