Vấn đề
Chúng tôi có một truy vấn như
SELECT COUNT(1)
FROM article
JOIN reservation ON a_id = r_article_id
WHERE r_last_modified < now() - '8 weeks'::interval
AND r_group_id = 1
AND r_status = 'OPEN';
Vì nó chạy vào thời gian chờ (sau 10 phút) thường xuyên hơn không, tôi quyết định điều tra vấn đề.
Đầu EXPLAIN (ANALYZE, BUFFERS)
ra trông như thế này:
Aggregate (cost=264775.48..264775.49 rows=1 width=0) (actual time=238960.290..238960.291 rows=1 loops=1)
Buffers: shared hit=200483 read=64361 dirtied=666 written=8, temp read=3631 written=3617
I/O Timings: read=169806.955 write=0.154
-> Hash Join (cost=52413.67..264647.65 rows=51130 width=0) (actual time=1845.483..238957.588 rows=21644 loops=1)
Hash Cond: (reservation.r_article_id = article.a_id)
Buffers: shared hit=200483 read=64361 dirtied=666 written=8, temp read=3631 written=3617
I/O Timings: read=169806.955 write=0.154
-> Index Scan using reservation_r_article_id_idx1 on reservation (cost=0.42..205458.72 rows=51130 width=4) (actual time=34.035..237000.197 rows=21644 loops=1)
Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
Rows Removed by Filter: 151549
Buffers: shared hit=200193 read=48853 dirtied=450 written=8
I/O Timings: read=168614.105 write=0.154
-> Hash (cost=29662.22..29662.22 rows=1386722 width=4) (actual time=1749.392..1749.392 rows=1386814 loops=1)
Buckets: 32768 Batches: 8 Memory Usage: 6109kB
Buffers: shared hit=287 read=15508 dirtied=216, temp written=3551
I/O Timings: read=1192.850
-> Seq Scan on article (cost=0.00..29662.22 rows=1386722 width=4) (actual time=23.822..1439.310 rows=1386814 loops=1)
Buffers: shared hit=287 read=15508 dirtied=216
I/O Timings: read=1192.850
Total runtime: 238961.812 ms
Nút thắt cổ chai rõ ràng là quét chỉ mục. Vì vậy, hãy xem định nghĩa chỉ mục:
CREATE INDEX reservation_r_article_id_idx1
ON reservation USING btree (r_article_id)
WHERE (r_status <> ALL (ARRAY['FULFILLED', 'CLOSED', 'CANCELED']));
Kích thước và số hàng
Kích thước của nó (được báo cáo bởi \di+
hoặc bằng cách truy cập tệp vật lý) là 36 MB. Vì các đặt phòng thường chỉ dành một khoảng thời gian tương đối ngắn trong tất cả các trạng thái không được liệt kê ở trên, có rất nhiều cập nhật xảy ra, vì vậy chỉ số này khá phình to (khoảng 24 MB bị lãng phí ở đây) - tuy nhiên, kích thước tương đối nhỏ.
Chiếc reservation
bàn có kích thước khoảng 3,8 GB, chứa khoảng 40 triệu hàng. Số lượng đặt phòng chưa được đóng là khoảng 170.000 (số chính xác được báo cáo trong nút quét chỉ mục ở trên).
Bây giờ thật bất ngờ: quét chỉ mục báo cáo tìm nạp một lượng lớn bộ đệm (nghĩa là, các trang 8 kb):
Buffers: shared hit=200193 read=48853 dirtied=450 written=8
Các số được đọc từ bộ đệm và đĩa (hoặc bộ đệm của hệ điều hành) thêm tới 1,9 GB!
Trường hợp xấu nhất
Mặt khác, trường hợp xấu nhất, khi mỗi bộ dữ liệu nằm trên một trang khác nhau của bảng, sẽ chiếm tài khoản truy cập (21644 + 151549) + 4608 trang (tổng số hàng được lấy từ bảng cộng với số trang chỉ mục từ vật lý kích thước). Con số này vẫn chỉ dưới 180.000 - thấp hơn nhiều so với mức gần 250.000 được quan sát.
Điều thú vị (và có thể quan trọng) là tốc độ đọc đĩa khoảng 2,2 MB / s, điều này khá bình thường, tôi đoán vậy.
Vậy thì sao?
Có ai có ý tưởng về sự khác biệt này có thể đến từ đâu không?
Lưu ý: Để rõ ràng, chúng tôi có ý tưởng cần cải thiện / thay đổi ở đây, nhưng tôi thực sự muốn hiểu những con số tôi nhận được - đây là những gì câu hỏi là về.
Cập nhật: kiểm tra hiệu quả của bộ nhớ đệm hoặc vi lọc
Dựa trên câu trả lời của jjanes , tôi đã kiểm tra xem điều gì sẽ xảy ra khi tôi chạy lại chính xác cùng một truy vấn. Số lượng bộ đệm bị ảnh hưởng không thực sự thay đổi. (Để làm điều này, tôi đã đơn giản hóa truy vấn đến mức tối thiểu mà vẫn hiển thị vấn đề.) Đây là những gì tôi thấy từ lần chạy đầu tiên:
Aggregate (cost=240541.52..240541.53 rows=1 width=0) (actual time=97703.589..97703.590 rows=1 loops=1)
Buffers: shared hit=413981 read=46977 dirtied=56
I/O Timings: read=96807.444
-> Index Scan using reservation_r_article_id_idx1 on reservation (cost=0.42..240380.54 rows=64392 width=0) (actual time=13.757..97698.461 rows=19236 loops=1)
Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
Rows Removed by Filter: 232481
Buffers: shared hit=413981 read=46977 dirtied=56
I/O Timings: read=96807.444
Total runtime: 97703.694 ms
và sau cái thứ hai:
Aggregate (cost=240543.26..240543.27 rows=1 width=0) (actual time=388.123..388.124 rows=1 loops=1)
Buffers: shared hit=460990
-> Index Scan using reservation_r_article_id_idx1 on reservation (cost=0.42..240382.28 rows=64392 width=0) (actual time=0.032..385.900 rows=19236 loops=1)
Filter: ((r_group_id = 1) AND (r_status = 'OPEN') AND (r_last_modified < (now() - '56 days'::interval)))
Rows Removed by Filter: 232584
Buffers: shared hit=460990
Total runtime: 388.187 ms
pg_stat_reset()
trên nó, sau đó chạy truy vấn, và sau đó nhìn vào pg_statio_user_tables
để xem nó thuộc tính các khối ở đâu.
article
không? Có vẻ như tất cả các cột liên quan là từreservation
bảng và (giả sử) có FK, kết quả sẽ giống nhau.