Saya menggunakan Postgres 9.3 melalui Heroku.
Saya memiliki tabel, "traffic", dengan catatan 1M + yang memiliki banyak sisipan dan pembaruan setiap hari. Saya perlu melakukan operasi SUM di tabel ini dalam rentang waktu yang berbeda dan panggilan tersebut dapat memakan waktu hingga 40 detik dan akan sangat senang mendengar saran tentang cara meningkatkannya.
Saya memiliki indeks berikut pada tabel ini:
CREATE INDEX idx_traffic_partner_only ON traffic (dt_created) WHERE campaign_id IS NULL AND uuid_self <> uuid_partner;
Ini adalah contoh pernyataan SELECT:
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'
Dan ini adalah EXPLAIN ANALYZE:
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
Pertanyaan ini sangat mirip dengan yang lain di SE, tetapi yang satu menggunakan indeks di dua rentang cap waktu kolom dan perencana indeks untuk kueri itu memiliki perkiraan yang jauh. Saran utama di sana adalah untuk membuat indeks multi-kolom yang diurutkan, tetapi untuk indeks kolom tunggal yang tidak memiliki banyak efek. Saran lainnya adalah menggunakan indeks CLUSTER / pg_repack dan GIST, tapi saya belum mencobanya, karena saya ingin melihat apakah ada solusi yang lebih baik menggunakan indeks reguler.
Mengoptimalkan kueri pada rentang cap waktu (dua kolom)
Untuk referensi, saya mencoba indeks berikut ini, yang tidak digunakan oleh DB:
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 JELASKAN (ANALISIS, VERBOSE, BIAYA, BUFFER) dan ini adalah hasil:
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
Definisi tabel:
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 adalah kunci utama dan uuid_self, uuid_partner, dan campaign_id adalah kunci asing. Bidang dt_updated diperbarui dengan fungsi postgres.
traffic
. Juga: mengapa yang kedua EXPLAIN
menunjukkan penurunan dari 42 detik menjadi 0,5 detik? Apakah jalankan pertama dengan cache dingin?
id
? Ada kendala lain? Saya melihat dua kolom yang bisa NULL. Berapa persentase nilai NULL di masing-masing? Apa yang kamu dapat untuk ini? SELECT count(*) AS ct, count(campaign_id)/ count(*) AS camp_pct, count(dt_updated)/count(*) AS upd_pct FROM traffic;
explain (buffers, analyze, verbose) ...
mungkin memberi lebih banyak cahaya.