Tôi đang sử dụng Postgres 9.3 thông qua Heroku.
Tôi có một bảng, "lưu lượng truy cập", với các bản ghi 1M + có nhiều chèn và cập nhật mỗi ngày. Tôi cần thực hiện các thao tác SUM trên bảng này trong các khoảng thời gian khác nhau và các cuộc gọi đó có thể mất tới 40 giây và rất thích nghe đề xuất về cách cải thiện điều đó.
Tôi có chỉ số sau thay thế trên bảng này:
CREATE INDEX idx_traffic_partner_only ON traffic (dt_created) WHERE campaign_id IS NULL AND uuid_self <> uuid_partner;
Dưới đây là một ví dụ câu lệnh CHỌN:
SELECT SUM("clicks") AS clicks, SUM("impressions") AS impressions
FROM "traffic"
WHERE "uuid_self" != "uuid_partner"
AND "campaign_id" is NULL
AND "dt_created" >= 'Sun, 29 Mar 2015 00:00:00 +0000'
AND "dt_created" <= 'Mon, 27 Apr 2015 23:59:59 +0000'
Và đây là PHÂN TÍCH GIẢI THÍCH:
Aggregate (cost=21625.91..21625.92 rows=1 width=16) (actual time=41804.754..41804.754 rows=1 loops=1)
-> Index Scan using idx_traffic_partner_only on traffic (cost=0.09..20085.11 rows=308159 width=16) (actual time=1.409..41617.976 rows=302392 loops=1)
Index Cond: ((dt_created >= '2015-03-29'::date) AND (dt_created <= '2015-04-27'::date))
Total runtime: 41804.893 ms
http://explain.depesz.com/s/gGA
Câu hỏi này rất giống với câu hỏi khác về SE, nhưng câu hỏi này đã sử dụng một chỉ mục trên hai phạm vi dấu thời gian của cột và trình hoạch định chỉ mục cho truy vấn đó có các ước tính đã bị loại bỏ. Gợi ý chính là tạo ra một chỉ mục nhiều cột được sắp xếp, nhưng đối với các chỉ mục cột đơn lẻ không có nhiều tác dụng. Các đề xuất khác là sử dụng các chỉ mục CLUSTER / pg numpack và GIST, nhưng tôi chưa thử chúng, vì tôi muốn xem liệu có giải pháp nào tốt hơn bằng cách sử dụng các chỉ mục thông thường.
Tối ưu hóa truy vấn trên một loạt dấu thời gian (hai cột)
Để tham khảo, tôi đã thử các chỉ mục sau, không được DB sử dụng:
INDEX idx_traffic_2 ON traffic (campaign_id, uuid_self, uuid_partner, dt_created);
INDEX idx_traffic_3 ON traffic (dt_created);
INDEX idx_traffic_4 ON traffic (uuid_self);
INDEX idx_traffic_5 ON traffic (uuid_partner);
EDIT : Ran GIẢI THÍCH (PHÂN TÍCH, ĐỘNG TỪ, CHI PHÍ, BUFFERS) và đây là những kết quả:
Aggregate (cost=20538.62..20538.62 rows=1 width=8) (actual time=526.778..526.778 rows=1 loops=1)
Output: sum(clicks), sum(impressions)
Buffers: shared hit=47783 read=29803 dirtied=4
I/O Timings: read=184.936
-> Index Scan using idx_traffic_partner_only on public.traffic (cost=0.09..20224.74 rows=313881 width=8) (actual time=0.049..431.501 rows=302405 loops=1)
Output: id, uuid_self, uuid_partner, impressions, clicks, dt_created... (other fields redacted)
Index Cond: ((traffic.dt_created >= '2015-03-29'::date) AND (traffic.dt_created <= '2015-04-27'::date))
Buffers: shared hit=47783 read=29803 dirtied=4
I/O Timings: read=184.936
Total runtime: 526.881 ms
http://explain.depesz.com/s/7Gu6
Bảng định nghĩa:
CREATE TABLE traffic (
id serial,
uuid_self uuid not null,
uuid_partner uuid not null,
impressions integer NOT NULL DEFAULT 1,
clicks integer NOT NULL DEFAULT 0,
campaign_id integer,
dt_created DATE DEFAULT CURRENT_DATE NOT NULL,
dt_updated TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
)
id là khóa chính và uuid_elf, uuid_partner và chiến dịch_id đều là khóa ngoại. Trường dt_updated được cập nhật với hàm postgres.
traffic
. Ngoài ra: tại sao cái thứ hai EXPLAIN
hiển thị giảm từ 42 giây xuống 0,5 giây? Là lần chạy đầu tiên với bộ đệm lạnh?
id
? Bất kỳ hạn chế khác? Tôi thấy hai cột có thể là NULL. Bao nhiêu phần trăm giá trị NULL trong mỗi? Bạn nhận được gì cho điều này? SELECT count(*) AS ct, count(campaign_id)/ count(*) AS camp_pct, count(dt_updated)/count(*) AS upd_pct FROM traffic;
explain (buffers, analyze, verbose) ...
có thể làm sáng tỏ hơn