Je revoyais juste un vieux code écrit pour PostgreSQL pré-8.4 , et j'ai vu quelque chose de vraiment chouette. Je me souviens avoir eu une fonction personnalisée pour faire une partie de cela dans la journée, mais j'ai oublié à quoi cela array_agg()
ressemblait. Pour examen, l'agrégation moderne est écrite comme ceci.
SELECT array_agg(x ORDER BY x DESC) FROM foobar;
Cependant, il était une fois, il était écrit comme ça,
SELECT ARRAY(SELECT x FROM foobar ORDER BY x DESC);
Donc, je l'ai essayé avec des données de test ..
CREATE TEMP TABLE foobar AS
SELECT * FROM generate_series(1,1e7)
AS t(x);
Les résultats ont été surprenants. La méthode #OldSchoolCool a été massivement plus rapide: une accélération de 25%. De plus, la simplifier sans l'ORDRE, a montré la même lenteur.
# 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)
Alors, qu'est-ce qui se passe ici. Pourquoi array_agg , une fonction interne est-elle tellement plus lente que le vaudou SQL du planificateur?
Utilisation de " PostgreSQL 9.5.5 sur x86_64-pc-linux-gnu, compilé par gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005, 64 bits"
array_agg
doit garder une trace de l'ordre de ses entrées où leARRAY
constructeur semble faire quelque chose à peu près équivalent à aUNION
comme expression en interne. Si je devais deviner, ilarray_agg
faudrait probablement plus de mémoire. Je n'ai pas été en mesure de le tester de manière exhaustive, mais sur PostgreSQL 9.6 fonctionnant sur Ubuntu 16.04, laARRAY()
requête avecORDER BY
utilisé une fusion externe et était plus lente que laarray_agg
requête. Comme vous l'avez dit, à moins de lire le code, votre réponse est la meilleure explication que nous ayons.