Nah, kedua kueri Anda berada di tabel yang berbeda (reportimpression
vs. reportimpressionday
), jadi perbandingan dua kueri sebenarnya bukan perbandingan. Apakah Anda ANALYZE
keduanya? Berbagai statistik kolom juga dapat berperan. Indeks atau tabel mengasapi mungkin berbeda. Apakah sebagian besar dari semua baris memenuhi syarat untuk Februari 2019? dll.
Satu bidikan dalam gelap, bandingkan persentase untuk kedua tabel:
SELECT tbl, round(share * 100 / total, 2) As percentage
FROM (
SELECT text 'reportimpression' AS tbl
, count(*)::numeric AS total
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')::numeric AS share
FROM reportimpression
UNION ALL
SELECT 'reportimpressionday'
, count(*)
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')
FROM reportimpressionday
) sub;
Apakah yang untuk reportimpression
lebih besar? Maka mungkin saja melebihi jumlah yang diharapkan dapat membantu indeks.
Secara umum, reportimpression_datelocal_index
indeks Anda pada (datelocal) terlihat bagus untuk itu, dan reportimpression_viewership_index
bahkan memungkinkan pemindaian hanya indeks jika autovacuum mengalahkan beban tulis di atas meja. (Meskipun impressions
&agegroup
hanya pengiriman mati untuk ini dan itu akan bekerja lebih baik tanpa).
Jawab
Anda mendapatkan 26.6 percent, and day is 26.4 percent
untuk pertanyaan saya. Untuk persentase sebesar itu, indeks biasanya tidak berguna sama sekali . Pemindaian berurutan biasanya merupakan cara tercepat. Hanya pemindaian indeks saja yang dapat masih masuk akal jika tabel yang mendasarinya jauh lebih besar. (Atau Anda memiliki parah tabel bloat, dan indeks yang lebih sedikit, yang membuat indeks lebih menarik lagi.)
Permintaan pertama Anda mungkin berada di titik kritis. Coba persempit kerangka waktu hingga Anda melihat pemindaian hanya indeks. Anda tidak akan melihat pemindaian indeks (bitmap) dengan lebih dari 5% dari semua baris yang memenuhi syarat (tergantung pada banyak faktor).
Permintaan
Bagaimanapun, pertimbangkan kueri yang dimodifikasi ini:
SELECT date_part('hour', datelocal) AS hour
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpression
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01' -- '2019-02-28' -- ?
GROUP BY 1
ORDER BY 1;
SELECT date_trunc('day', datelocal) AS day
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpressionday
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01'
GROUP BY 1
ORDER BY 1;
Poin utama
-
Saat menggunakan format tanggal yang dilokalkan seperti
'2-1-2019'
, bukato_timestamp()
dengan penentu format eksplisit. Kalau tidak, ini tergantung pada pengaturan lokal dan mungkin rusak (diam-diam) ketika dipanggil dari sesi dengan pengaturan yang berbeda. Sebaiknya gunakan format tanggal/waktu ISO seperti yang ditunjukkan yang tidak bergantung pada pengaturan lokal. -
Sepertinya Anda ingin menyertakan seluruh bulan dari Februari. Tetapi kueri Anda meleset dari batas atas. Untuk satu, Februari mungkin memiliki 29 hari. Sebuah
datelocal < '2-28-2019'
tidak termasuk semua 28 Februari juga. Gunakandatelocal < '2019-03-01'
sebagai gantinya. -
Lebih murah untuk mengelompokkan &mengurutkan menurut ekspresi yang sama seperti yang Anda miliki di
SELECT
daftar jika Anda bisa. Jadi gunakandate_trunc()
di sana juga. Jangan gunakan ekspresi yang berbeda tanpa perlu. Jika Anda membutuhkan bagian tanggal dalam hasil, terapkan pada ekspresi yang dikelompokkan, seperti:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Kode sedikit lebih berisik, tetapi lebih cepat (dan mungkin lebih mudah untuk dioptimalkan untuk perencana kueri juga).
-
Gunakan agregat
FILTER
klausa di Postgres 9.4 atau lebih baru. Ini lebih bersih dan sedikit lebih cepat. Lihat: