Stavo solo rivedendo un vecchio codice scritto per PostgreSQL pre-8.4 e ho visto qualcosa di veramente elegante. Ricordo di avere una funzione personalizzata per fare un po 'di tutto ciò nel corso della giornata, ma ho dimenticato come era pre array_agg()
. Per la revisione, l'aggregazione moderna è scritta in questo modo.
SELECT array_agg(x ORDER BY x DESC) FROM foobar;
Tuttavia, una volta, è stato scritto in questo modo,
SELECT ARRAY(SELECT x FROM foobar ORDER BY x DESC);
Quindi, l'ho provato con alcuni dati di test ..
CREATE TEMP TABLE foobar AS
SELECT * FROM generate_series(1,1e7)
AS t(x);
I risultati sono stati sorprendenti .. Il modo #OldSchoolCool è stato enormemente più veloce: uno speedup del 25%. Inoltre, semplificandolo senza l'ORDINE, ha mostrato la stessa lentezza.
# 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)
Quindi, cosa sta succedendo qui. Perché array_agg , una funzione interna è molto più lenta del voodoo SQL del planner?
Utilizzando " PostgreSQL 9.5.5 su x86_64-pc-linux-gnu, compilato da gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005, 64-bit"
array_agg
deve tenere traccia dell'ordine dei suoi input in cui ilARRAY
costruttore sembra fare qualcosa di approssimativamente equivalente a aUNION
come espressione internamente. Se dovessi avventurarmi in un'ipotesi,array_agg
probabilmente richiederebbe più memoria. Non sono stato in grado di testare esaurientemente questo, ma su PostgreSQL 9.6 in esecuzione su Ubuntu 16.04 laARRAY()
query con haORDER BY
usato un'unione esterna ed è stata più lenta dellaarray_agg
query. Come hai detto, a meno di leggere il codice, la tua risposta è la migliore spiegazione che abbiamo.