我需要一些幫助來分析在包含83660.142萬行的大型表上執行的查詢的性能不佳,這需要25分鐘到一個多小時,取決於系統負載,用於計算。postgresql 9.6.4:大型表上的時間戳範圍查詢需要永久
我創建了下表,它由一個複合鍵和3個指標:
CREATE TABLE IF NOT EXISTS ds1records(
userid INT DEFAULT 0,
clientid VARCHAR(255) DEFAULT '',
ts TIMESTAMP,
site VARCHAR(50) DEFAULT '',
code VARCHAR(400) DEFAULT '');
CREATE UNIQUE INDEX IF NOT EXISTS primary_idx ON records (userid, clientid, ts, site, code);
CREATE INDEX IF NOT EXISTS userid_idx ON records (userid);
CREATE INDEX IF NOT EXISTS ts_idx ON records (ts);
CREATE INDEX IF NOT EXISTS userid_ts_idx ON records (userid ASC,ts DESC);
在春天批處理應用程序,我執行一個查詢,如下所示:
SELECT *
FROM records
WHERE userid = ANY(VALUES (2), ..., (96158 more userids))
AND (ts < '2017-09-02' AND ts >= '2017-09-01'
OR ts < '2017-08-26' AND ts >= '2017-08-25'
OR ts < '2017-08-19' AND ts >= '2017-08-18'
OR ts < '2017-08-12' AND ts >= '2017-08-11')
用戶ID在運行時確定(id的數字在95.000和110.000之間)。對於每個用戶,我需要提取當天的日期和最後三個工作日的頁面瀏覽量。查詢總是返回3-4M行之間的行。
使用EXPLAIN ANALYZE
選項執行查詢將返回以下執行計劃。
Nested Loop (cost=1483.40..1246386.43 rows=3761735 width=70) (actual time=108.856..1465501.596 rows=3643240 loops=1)
-> HashAggregate (cost=1442.38..1444.38 rows=200 width=4) (actual time=33.277..201.819 rows=96159 loops=1)
Group Key: "*VALUES*".column1
-> Values Scan on "*VALUES*" (cost=0.00..1201.99 rows=96159 width=4) (actual time=0.006..11.599 rows=96159 loops=1)
-> Bitmap Heap Scan on records (cost=41.02..6224.01 rows=70 width=70) (actual time=8.865..15.218 rows=38 loops=96159)
Recheck Cond: (userid = "*VALUES*".column1)
Filter: (((ts < '2017-09-02 00:00:00'::timestamp without time zone) AND (ts >= '2017-09-01 00:00:00'::timestamp without time zone)) OR ((ts < '2017-08-26 00:00:00'::timestamp without time zone) AND (ts >= '2017-08-25 00:00:00'::timestamp without time zone)) OR ((ts < '2017-08-19 00:00:00'::timestamp without time zone) AND (ts >= '2017-08-18 00:00:00'::timestamp without time zone)) OR ((ts < '2017-08-12 00:00:00'::timestamp without time zone) AND (ts >= '2017-08-11 00:00:00'::timestamp without time zone)))
Rows Removed by Filter: 792
Heap Blocks: exact=77251145
-> Bitmap Index Scan on userid_ts_idx (cost=0.00..41.00 rows=1660 width=0) (actual time=6.593..6.593 rows=830 loops=96159)
Index Cond: (userid = "*VALUES*".column1)
我已經調整了一些Postgres的調整參數(可惜沒有成功)的值:
- effective_cache_size = 15GB(可能是無用的查詢只執行一次)
- 的shared_buffers = 15GB
- work_mem = 3GB
該應用程序運行計算上昂貴的任務(例如。數據融合/數據注入),並消耗大約100GB的內存,所以系統硬件的尺寸足夠大,配備125GB RAM和16個內核(操作系統:Debian)。
我想知道爲什麼postgres在其執行計劃中不使用組合索引userid_ts_idx
?由於索引中的時間戳列以相反的順序排序,因此我希望postgres使用它來查找查詢範圍部分的匹配元組,因爲它可以順序遍歷索引,直到條件ts < '2017-09-02 00:00:00
爲真,並返回所有值直到條件爲止符合ts >= 2017-09-01 00:00:00
。相反,postgres使用昂貴的位圖堆掃描,如果我理解正確,它會進行線性表掃描。我錯誤配置了數據庫設置還是存在概念誤解?
更新
的CTE作爲意見提出可惜沒不帶來任何改善。位圖堆掃描已被Sequantial Scan取代,但性能仍然很差。以下是更新的執行計劃:
Merge Join (cost=20564929.37..20575876.60 rows=685277 width=106) (actual time=2218133.229..2222280.192 rows=3907472 loops=1)
Merge Cond: (ids.id = r.userid)
Buffers: shared hit=2408684 read=181785
CTE ids
-> Values Scan on "*VALUES*" (cost=0.00..1289.70 rows=103176 width=4) (actual time=0.002..28.670 rows=103176 loops=1)
CTE ts
-> Values Scan on "*VALUES*_1" (cost=0.00..0.05 rows=4 width=32) (actual time=0.002..0.004 rows=4 loops=1)
-> Sort (cost=10655.37..10913.31 rows=103176 width=4) (actual time=68.476..83.312 rows=103176 loops=1)
Sort Key: ids.id
Sort Method: quicksort Memory: 7909kB
-> CTE Scan on ids (cost=0.00..2063.52 rows=103176 width=4) (actual time=0.007..47.868 rows=103176 loops=1)
-> Sort (cost=20552984.25..20554773.54 rows=715717 width=102) (actual time=2218059.941..2221230.585 rows=8085760 loops=1)
Sort Key: r.userid
Sort Method: quicksort Memory: 1410084kB
Buffers: shared hit=2408684 read=181785
-> Nested Loop (cost=0.00..20483384.24 rows=715717 width=102) (actual time=885849.043..2214665.723 rows=8085767 loops=1)
Join Filter: (ts.r @> r.ts)
Rows Removed by Join Filter: 707630821
Buffers: shared hit=2408684 read=181785
-> Seq Scan on records r (cost=0.00..4379760.52 rows=178929152 width=70) (actual time=0.024..645616.135 rows=178929147 loops=1)
Buffers: shared hit=2408684 read=181785
-> CTE Scan on ts (cost=0.00..0.08 rows=4 width=32) (actual time=0.000..0.000 rows=4 loops=178929147)
Planning time: 126.110 ms
Execution time: 2222514.566 ms
有沒有機會受磁盤讀取限制?下次請使用'EXPLAIN(ANALYZE,BUFFERS)'。這會讓你對緩衝有所瞭解。正如我們所看到的,堆掃描消耗大部分時間。 https://explain.depesz.com/s/wJBk – filiprem
感謝提示...根據* iotop *磁盤讀數波動在1和7 M/s之間,但我也看到一些峯值在17M/s 。一個好的表現應該是什麼水平? – user35934
在這組日期範圍中有幾個OR,我認爲它不會「保持」最近的日期向後推移到最早的給定日期。過濾器指示它處理每個範圍'(...或...)和(...或...)和(...或...)和(...或...)' –