5

Ich bin auf PostgreSQL 9.3. Dies sollte auf jedem Tisch mit mehr als 100.000 Zeilen reproduzieren. Die EXPLAIN ANALYZE zeigt viel mehr Zeilen, die mit LIMIT 2 gescannt wurden, aber ich kann nicht herausfinden warum.Warum nimmt LIMIT 2 in dieser Abfrage Größenordnungen länger als LIMIT 1?

Limit 1:

EXPLAIN ANALYZE WITH base AS (
    SELECT *, ROW_NUMBER() OVER() AS rownum FROM a_big_table 
), filter AS (
    SELECT rownum, true AS thing FROM base 
) SELECT * FROM base LEFT JOIN filter USING (rownum) WHERE filter.thing LIMIT 1 

Ergebnis:

Limit (cost=283512.19..283517.66 rows=1 width=2114) (actual time=0.019..0.019 rows=1 loops=1) 
    CTE base 
    -> WindowAgg (cost=0.00..188702.69 rows=4740475 width=101) (actual time=0.008..0.008 rows=1 loops=1) 
      -> Seq Scan on a_big_table (cost=0.00..129446.75 rows=4740475 width=101) (actual time=0.003..0.003 rows=1 loops=1) 
    CTE filter 
    -> CTE Scan on base base_1 (cost=0.00..94809.50 rows=4740475 width=8) (actual time=0.000..0.000 rows=1 loops=1) 
    -> Nested Loop (cost=0.00..307677626611.24 rows=56180269915 width=2114) (actual time=0.018..0.018 rows=1 loops=1) 
     Join Filter: (base.rownum = filter.rownum) 
     -> CTE Scan on base (cost=0.00..94809.50 rows=4740475 width=2113) (actual time=0.011..0.011 rows=1 loops=1) 
     -> CTE Scan on filter (cost=0.00..94809.50 rows=2370238 width=9) (actual time=0.002..0.002 rows=1 loops=1) 
       Filter: thing 
Total runtime: 0.057 ms 

Limit 2:

EXPLAIN ANALYZE WITH base AS (
    SELECT *, ROW_NUMBER() OVER() AS rownum FROM a_big_table 
), filter AS (
    SELECT rownum, true AS thing FROM base 
) SELECT * FROM base LEFT JOIN filter USING (rownum) WHERE filter.thing LIMIT 2 

Ergebnis:

Limit (cost=283512.19..283523.14 rows=2 width=2114) (actual time=0.018..14162.283 rows=2 loops=1) 
    CTE base 
    -> WindowAgg (cost=0.00..188702.69 rows=4740475 width=101) (actual time=0.008..4443.359 rows=4714243 loops=1) 
      -> Seq Scan on a_big_table (cost=0.00..129446.75 rows=4740475 width=101) (actual time=0.002..1421.622 rows=4714243 loops=1) 
    CTE filter 
    -> CTE Scan on base base_1 (cost=0.00..94809.50 rows=4740475 width=8) (actual time=0.001..10214.684 rows=4714243 loops=1) 
    -> Nested Loop (cost=0.00..307677626611.24 rows=56180269915 width=2114) (actual time=0.018..14162.280 rows=2 loops=1) 
     Join Filter: (base.rownum = filter.rownum) 
     Rows Removed by Join Filter: 4714243 
     -> CTE Scan on base (cost=0.00..94809.50 rows=4740475 width=2113) (actual time=0.011..0.028 rows=2 loops=1) 
     -> CTE Scan on filter (cost=0.00..94809.50 rows=2370238 width=9) (actual time=0.009..6595.770 rows=2357122 loops=2) 
       Filter: thing 
Total runtime: 14247.374 ms 
+1

CTEs wirkt wie Optimierungszäune in PostgreSQL. Versuchen Sie stattdessen, Ihre Abfrage mit Unterauswahl erneut zu schreiben. – vyegorov

+0

Ist das Zaunverhalten vom Wert von LIMIT abhängig? Wenn das irgendwo dokumentiert ist, konnte ich es nicht finden. – rcrogers

Antwort

1

Motor läuft zuerst, dann begrenzt. Sie können also viel mehr Zeilen sehen.

+1

Können Sie das ein bisschen mehr erklären? Die 'explain'-Ausgabe zeigt (für mich) an, dass die Scans wiederholt werden, um die Anzahl der Zeilen zu erzeugen, die mit 'LIMIT' spezifiziert wurden. – mabi