Bảng của tôi trông như sau:
Column | Type |
-----------------------+-------------------+
id | integer |
source_id | integer |
timestamp | integer |
observation_timestamp | integer |
value | double precision |
các chỉ mục tồn tại trên source_id, dấu thời gian và trên một tổ hợp dấu thời gian và id ( CREATE INDEX timeseries_id_timestamp_combo_idx ON timeseries (id, timeseries DESC NULLS LAST)
)
Có 20M hàng trong đó (OK, có 120M, nhưng 20M với source_id = 1). Nó có nhiều mục giống nhau timestamp
với sự thay đổi observation_timestamp
, mô tả một sự kiện value
xảy ra tại timestamp
báo cáo hoặc quan sát tại observation_timestamp
. ví dụ: Nhiệt độ dự đoán cho 2 giờ chiều mai như dự đoán hôm nay lúc 12 giờ sáng.
Lý tưởng nhất là bảng này làm một vài điều tốt:
- hàng loạt chèn các mục mới, đôi khi 100K một lần
- chọn dữ liệu quan sát cho bộ đếm thời gian ("dự đoán nhiệt độ cho tháng 1 đến tháng 3")
- chọn dữ liệu được quan sát cho các bộ đếm thời gian như được quan sát từ một điểm nhất định ("quan điểm của các dự đoán nhiệt độ cho tháng 1 đến tháng 3 như chúng ta nghĩ vào ngày 1 tháng 11")
Câu hỏi thứ hai là câu hỏi chính.
Dữ liệu trong bảng sẽ trông như sau
id source_id timestamp observation_timestamp value
1 1 1531084900 1531083900 9999
2 1 1531084900 1531082900 1111
3 1 1531085900 1531083900 8888
4 1 1531085900 1531082900 7777
5 1 1531086900 1531082900 5555
và một đầu ra của truy vấn sẽ trông như sau (chỉ có hàng của obs_timestamp mới nhất được đại diện)
id source_id timestamp observation_timestamp value
1 1 1531084900 1531083900 9999
3 1 1531085900 1531083900 8888
5 1 1531086900 1531082900 5555
Tôi đã tham khảo một số tài liệu trước đó để tối ưu hóa các truy vấn này, cụ thể là
- /programming/25536422/optizes-group-by-query-to-retrieve-latest-record-per-user/25536748#25536748
- Làm cách nào để DISTINCT ON nhanh hơn trong PostgreSQL?
- /programming/3800551/select-first-row-in-each-group-by-group
... với thành công hạn chế.
Tôi đã cân nhắc việc tạo một bảng riêng biệt với timestamp
nó để dễ dàng tham khảo về sau hơn, nhưng do tính tương đối cao của những người tôi nghi ngờ liệu họ có giúp tôi không - ngoài ra tôi lo ngại rằng nó sẽ cản trở việc thực hiện batch inserting new entries
.
Tôi đang xem xét ba truy vấn và tất cả chúng đều cho tôi hiệu suất kém
- CTE đệ quy với LATITH tham gia
- Chức năng cửa sổ
- KHOẢNG CÁCH TRÊN
(Tôi biết rằng họ không hoàn toàn làm điều tương tự vào lúc này, nhưng họ phục vụ như những minh họa tốt về loại truy vấn theo như tôi thấy.)
CTE đệ quy với LATITH tham gia
WITH RECURSIVE cte AS (
(
SELECT ts
FROM timeseries ts
WHERE source_id = 1
ORDER BY id, "timestamp" DESC NULLS LAST
LIMIT 1
)
UNION ALL
SELECT (
SELECT ts1
FROM timeseries ts1
WHERE id > (c.ts).id
AND source_id = 1
ORDER BY id, "timestamp" DESC NULLS LAST
LIMIT 1
)
FROM cte c
WHERE (c.ts).id IS NOT NULL
)
SELECT (ts).*
FROM cte
WHERE (ts).id IS NOT NULL
ORDER BY (ts).id;
Hiệu suất:
Sort (cost=164999681.98..164999682.23 rows=100 width=28)
Sort Key: ((cte.ts).id)
CTE cte
-> Recursive Union (cost=1653078.24..164999676.64 rows=101 width=52)
-> Subquery Scan on *SELECT* 1 (cost=1653078.24..1653078.26 rows=1 width=52)
-> Limit (cost=1653078.24..1653078.25 rows=1 width=60)
-> Sort (cost=1653078.24..1702109.00 rows=19612304 width=60)
Sort Key: ts.id, ts.timestamp DESC NULLS LAST
-> Bitmap Heap Scan on timeseries ts (cost=372587.92..1555016.72 rows=19612304 width=60)
Recheck Cond: (source_id = 1)
-> Bitmap Index Scan on ix_timeseries_source_id (cost=0.00..367684.85 rows=19612304 width=0)
Index Cond: (source_id = 1)
-> WorkTable Scan on cte c (cost=0.00..16334659.64 rows=10 width=32)
Filter: ((ts).id IS NOT NULL)
SubPlan 1
-> Limit (cost=1633465.94..1633465.94 rows=1 width=60)
-> Sort (cost=1633465.94..1649809.53 rows=6537435 width=60)
Sort Key: ts1.id, ts1.timestamp DESC NULLS LAST
-> Bitmap Heap Scan on timeseries ts1 (cost=369319.21..1600778.77 rows=6537435 width=60)
Recheck Cond: (source_id = 1)
Filter: (id > (c.ts).id)
-> Bitmap Index Scan on ix_timeseries_source_id (cost=0.00..367684.85 rows=19612304 width=0)
Index Cond: (source_id = 1)
-> CTE Scan on cte (cost=0.00..2.02 rows=100 width=28)
Filter: ((ts).id IS NOT NULL)
(chỉ EXPLAIN
, EXPLAIN ANALYZE
không thể hoàn thành, mất> 24 giờ để hoàn thành truy vấn)
Chức năng cửa sổ
WITH summary AS (
SELECT ts.id, ts.source_id, ts.value,
ROW_NUMBER() OVER(PARTITION BY ts.timestamp ORDER BY ts.observation_timestamp DESC) AS rn
FROM timeseries ts
WHERE source_id = 1
)
SELECT s.*
FROM summary s
WHERE s.rn = 1;
Hiệu suất:
CTE Scan on summary s (cost=5530627.97..5971995.66 rows=98082 width=24) (actual time=150368.441..226331.286 rows=88404 loops=1)
Filter: (rn = 1)
Rows Removed by Filter: 20673704
CTE summary
-> WindowAgg (cost=5138301.13..5530627.97 rows=19616342 width=32) (actual time=150368.429..171189.504 rows=20762108 loops=1)
-> Sort (cost=5138301.13..5187341.98 rows=19616342 width=24) (actual time=150368.405..165390.033 rows=20762108 loops=1)
Sort Key: ts.timestamp, ts.observation_timestamp DESC
Sort Method: external merge Disk: 689752kB
-> Bitmap Heap Scan on timeseries ts (cost=372675.22..1555347.49 rows=19616342 width=24) (actual time=2767.542..50399.741 rows=20762108 loops=1)
Recheck Cond: (source_id = 1)
Rows Removed by Index Recheck: 217784
Heap Blocks: exact=48415 lossy=106652
-> Bitmap Index Scan on ix_timeseries_source_id (cost=0.00..367771.13 rows=19616342 width=0) (actual time=2757.245..2757.245 rows=20762630 loops=1)
Index Cond: (source_id = 1)
Planning time: 0.186 ms
Execution time: 234883.090 ms
KHOẢNG CÁCH TRÊN
SELECT DISTINCT ON (timestamp) *
FROM timeseries
WHERE source_id = 1
ORDER BY timestamp, observation_timestamp DESC;
Hiệu suất:
Unique (cost=5339449.63..5437531.34 rows=15991 width=28) (actual time=112653.438..121397.944 rows=88404 loops=1)
-> Sort (cost=5339449.63..5388490.48 rows=19616342 width=28) (actual time=112653.437..120175.512 rows=20762108 loops=1)
Sort Key: timestamp, observation_timestamp DESC
Sort Method: external merge Disk: 770888kB
-> Bitmap Heap Scan on timeseries (cost=372675.22..1555347.49 rows=19616342 width=28) (actual time=2091.585..56109.942 rows=20762108 loops=1)
Recheck Cond: (source_id = 1)
Rows Removed by Index Recheck: 217784
Heap Blocks: exact=48415 lossy=106652
-> Bitmap Index Scan on ix_timeseries_source_id (cost=0.00..367771.13 rows=19616342 width=0) (actual time=2080.054..2080.054 rows=20762630 loops=1)
Index Cond: (source_id = 1)
Planning time: 0.132 ms
Execution time: 161651.006 ms
Tôi nên cấu trúc dữ liệu của mình như thế nào, có quét không nên ở đó không, nói chung có thể đưa các truy vấn này đến ~ 1 giây (thay vì ~ 120 giây) không?
Có cách nào khác để truy vấn dữ liệu để có được kết quả tôi muốn không?
Nếu không, tôi nên xem xét cơ sở hạ tầng / kiến trúc khác nhau?
LIMIT
câu hỏi và thêm đầu ra với EXPLAIN ANALYZE
(chỉ EXPLAIN
trên recursive
một phần)