Postgresql
DISTINCT ON vs ROW_NUMBER() 用於獲取具有組最大值的行
我在 PostgreSQL 9.4 中有下表:
CREATE TABLE dpa( id serial NOT NULL, currency_id integer, amount numeric(14,3), date timestamp without time zone, plat_id integer, pl_id integer, p_id integer, CONSTRAINT dpa_pkey PRIMARY KEY (id), )
和設置:
work_mem = 128MB table_size = 16 MB
和索引:
CREATE INDEX idx1 ON dpa USING btree (plat_id, p_id, pl_id, currency_id, date DESC NULLS LAST, amount)
該表由大約
242K
行組成。我對列沒有NOT NULL
限制,但它們實際上是NOT NULL
.現在,我正在測量查詢的性能:
一世
SELECT plat_id, p_id, pl_id, player_account player_account FROM( SELECT plat_id, p_id, pl_id, COALESCE(amount, 0) player_account, ROW_NUMBER() OVER (PARTITION BY plat_id, p_id, pl_id, currency_id ORDER BY date DESC NULLS LAST) rn FROM dpa ) sub WHERE rn = 1;
分析方案:
Subquery Scan on sub (cost=0.42..25484.16 rows=1214 width=44) (actual time=0.044..296.810 rows=215274 loops=1) Filter: (sub.rn = 1) Rows Removed by Filter: 27556 -> WindowAgg (cost=0.42..22448.79 rows=242830 width=28) (actual time=0.043..255.690 rows=242830 loops=1) -> Index Only Scan using idx1 on dpa (cost=0.42..16378.04 rows=242830 width=28) (actual time=0.037..91.576 rows=242830 loops=1)" Heap Fetches: 242830
伊爾
SELECT DISTINCT ON(plat_id, p_id, pl_id, currency_id) plat_id, p_id, pl_id, currency_id, amount FROM dpa ORDER BY plat_id, p_id, pl_id, currency_id, date DESC NULLS LAST
分析方案:
Unique (cost=0.42..18794.73 rows=82273 width=28) (actual time=0.017..128.277 rows=215274 loops=1) -> Index Only Scan using idx1 on dpa (cost=0.42..16366.43 rows=242830 width=28) (actual time=0.016..72.110 rows=242830 loops=1) Heap Fetches: 242830
可以看出,第二個查詢比第一個查詢快。但是當我執行這個查詢時,
PGAdmin
我得到了以下平均統計數據:帶有
ROW_NUMBER()
(第一個)的查詢:4999 ms
帶有
DISTINCT ON
(第二個)的查詢:5654 ms
我知道
bandwith
/latency
這麼大的結果集的成本很大。所有查詢都會產生215274
行。***問題:***為什麼在第二種情況下接收所有行比在第一種情況下需要更多的時間,儘管計劃器顯示第二種計劃更優化?
您看到的時間由 pgAdmin 給出(但它可以是任何其他客戶端)——這意味著它顯示了獲取和呈現輸出所需的時間。正如您知道數據庫生成數據所需的時間(通過使用
EXPLAIN ANALYZE
),您看到的差異必須來自傳輸和/或渲染。例如,您在第一個查詢中顯示的列較少,這可能是一個原因。如果您想了解傳輸過程中消耗了多少時間,您可以從應用程序中計算執行查詢的時間。如果您只獲取數據但不以任何方式處理它(更不用說渲染它),您可以很好地估計傳輸數據所需的時間。只需花費獲取數據所需的時間並減去(已知的)數據庫執行時間。
這樣,通過將上述數字與它提供給您的數字進行比較,您也會對 pgAdmin 的渲染時間有所了解。