Postgresql

為什麼 array_agg() 比非聚合 ARRAY() 建構子慢?

  • February 25, 2020

我只是在回顧一些為pre-8.4 PostgreSQL編寫的舊程式碼,我看到了一些非常漂亮的東西。我記得以前有一個自定義函式可以做一些這樣的事情,但我忘記了 pre- 是什麼array_agg()樣子的。回顧一下,現代聚合是這樣寫的。

SELECT array_agg(x ORDER BY x DESC) FROM foobar;

然而,曾幾何時,它是這樣寫的,

SELECT ARRAY(SELECT x FROM foobar ORDER BY x DESC);

所以,我用一些測試數據進行了嘗試..

CREATE TEMP TABLE foobar AS
SELECT * FROM generate_series(1,1e7)
 AS t(x);

結果令人驚訝。#OldSchoolCool 方式大大加快了速度:25% 的加速。此外,在沒有ORDER 的情況下簡化它,表現出同樣的緩慢。

# 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)

那麼,這裡發生了什麼。為什麼內部函式array_agg比規劃器的 SQL voodoo 慢得多?

在 x86_64-pc-linux-gnu 上使用“ PostgreSQL 9.5.5,由 gcc (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005, 64 位編譯”

關於ARRAY 建構子,沒有什麼“老派”或“過時”的(就是這樣ARRAY(SELECT x FROM foobar))。它一如既往的現代。將它用於簡單的數組聚合。

手冊:

也可以從子查詢的結果構造一個數組。在這種形式中,數組建構子是用關鍵字ARRAY後跟括號(非括號)子查詢編寫的。

聚合函式array_agg()更通用,因為它可以集成到SELECT具有更多列的列表中,可能在同一 中進行更多聚合SELECT,並且可以使用 組成任意組GROUP BY。雖然 ARRAY 建構子只能從SELECT返回單個列中返回單個數組。

我沒有研究原始碼,但顯然更通用的工具也更昂貴。

{}一個顯著的區別:如果沒有行符合條件,ARRAY 建構子返回一個空數組 ( )。array_agg()返回NULL相同。

引用自:https://dba.stackexchange.com/questions/159710