Özyinelemeli bir CTE'nin kardinalitesini nasıl 'ima ederim'?


10

Aşağıdaki özyinelemeli CTE'yi en az örnek olarak kullanıyorum, ancak genel olarak, iyileştirici özyinelemeli CTE'ler için varsayılan 'tahmin edilen' kardinaliteleri kullanmak zorunda:

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
*/

Not rows=31tahmin edilen ve rows=5yukarıdaki planında gerçek kardinallikleri. Bazı durumlarda 100 tahmin olarak kullanılmış gibi görünüyor, tahminlerin ardındaki mantığın tam olarak ne olduğundan emin değilim.

Gerçek dünya sorunumda, zayıf kardinalite tahmini hızlı bir 'iç içe döngüler' planının seçilmesini engelliyor. Özyinelemeli bir CTE'nin bu soruna geçici bir çözüm bulması için en iyileştirici kardinalitesini nasıl 'ipucu' edebilirim?


5
Bu, istatistik ipuçlarının gerçekten güzel olacağı birçok durumdan biridir. Orada COSTama çok başka, fonksiyonları üzerine. Ben pgsql-hackerlar üzerinde yükseltmek öneriyoruz, ama sadece "ipuçları" tartışmanın nth yineleme, sıcak hava kütleleri israf ve hiçbir şey elde sıkışmış yakalanacaktı :-(
Craig Ringer

Yanıtlar:


8

Sorunu bu şekilde çalıştım, ancak daha az karmaşık bir yol olduğunu umuyorum:

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)
*/
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.