Urutan kolom dalam indeks gabungan dalam PostgreSQL (dan urutan permintaan)

9

Saya punya meja dengan 50 ribu baris. Ini sebenarnya adalah tabel PostGIS.

Kueri memiliki 4 bagian (1 wajib) (3 Opsional)

  1. kotak persimpangan (kotak geografi) dengan 4 lat, panjang (saya menggunakan st_intersects) [Wajib]
  2. Rentang Tanggal (min, maks) pada bidang tanggal
  3. Jenis file (satu set hingga 8 nilai teks) saat ini menggunakan IN (.....) tapi saya bisa membuat tabel temp jika diperlukan. Saya melihat banyak orang tidak suka IN.
  4. Negara (nilai teks).

Saya berharap sekitar 100 - 4.000 baris yang dikembalikan

Jika saya membuat indeks gabungan pada tabel, kolom mana yang harus saya gunakan terlebih dahulu. Butiran halus mungkin lokasi (data tersebar di seluruh dunia). Saat ini saya memilikinya sebagai indeks GIST.

Indeks lainnya adalah BTREE.

Intuisi saya mengatakan gunakan berbutir halus, dan tentu saja bertahan. Misalnya hanya ada sekitar 12 jenis file, sehingga itu akan menjadi ember yang sangat besar untuk indeks.

Apa yang dikatakan guru PostgreSQL dan PostGIS (yang mengetahui internal sistem)?


MEMPERBARUI:

Biarkan saya mempertajam pertanyaan ini.

  1. Saya tidak ingin ada yang harus melakukan pekerjaan yang harus saya lakukan. Saya terlalu menghargai waktu Anda. Jadi saya akan menjelaskan analisis nanti.
  2. Yang saya cari hanyalah beberapa petunjuk dan tips serta panduan.
  3. Saya membaca posting kecil yang luar biasa ini: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes tentang indeks
  4. Apa yang biasanya saya lakukan adalah membuat 4 indeks terpisah (geo-box, nama negara, file_type, dan tanggal) tetapi apa yang ingin dilihat apa yang akan dilakukan permintaan komposit.

Katakan padaku apakah ada asumsi yang salah. (Saya cukup baru dengan gagasan indeks gabungan)

  1. Ketertiban itu penting. Pilih sebagai indeks pertama yang akan memotong baris paling banyak (dalam kasus saya lokasi (geografi) yang merupakan poligon sederhana atau multi-poligon akan melakukan yang terbaik).
  2. Terkadang kueri akan melewati indeks. Tetapi jika saya membuat kueri gabungan dengan kunci (# 1, # 2, # 3, # 4) maka bahkan jika pengguna membuat sesuatu yang meminta # 1, # 3 perencana masih akan menggunakan permintaan komposit tunggal, karena mereka memesan dipertahankan.
  3. Biasanya saya akan membuat tiga query BTREE, dan satu GIST (untuk tipe geografi). PostGIS tidak mendukung pembuatan gabungan dari beberapa tipe indeks. Jadi saya harus menggunakan GIST indeks gabungan. Tapi itu seharusnya tidak menyakiti hal-hal.
  4. Jika saya membuat beberapa senyawa tambahan atau indeks nilai tunggal, perencana cukup pintar untuk memilih yang paling cerdas .....
  5. Nama Negara dapat memiliki sekitar 250 nilai yang berbeda, dan jelas sangat terkait dengan lokasi (geobox), tetapi jika indeks terbaik berikutnya untuk mengurangi ukuran baris adalah file_type saya harus menggunakannya berikutnya. Saya tidak berharap para pengguna sering menggunakan negara atau tanggal dalam set kueri mereka.
  6. Saya TIDAK perlu khawatir membuat indeks gabungan 4 kunci akan sangat meningkatkan ukuran data indeks. Yaitu jika indeks satu-kunci akan menjadi 90% dari peningkatan kinerja, tidak ada salahnya untuk menambahkan 3 item lagi untuk membuatnya bertambah. Sebaliknya, saya harus benar-benar membuat kedua indeks. Indeks geografi tunggal, dan juga indeks gabungan, dan biarkan perencana mencari tahu mana yang terbaik, dan itu akan memperhitungkan ukuran tabel indeks.

Sekali lagi, saya tidak meminta siapa pun untuk merancang solusi saya, saya tidak melihat pekerjaan orang lain. Tetapi saya memang membutuhkan hal-hal yang tidak dijelaskan oleh dokumentasi PostGreSQL tentang implementasi

[Alasan saya belum memiliki hasil EXPLAIN untuk ditampilkan, adalah bahwa saya harus membuat tabel baris 25K ini dari tabel baris 24M. Butuh lebih banyak waktu daripada yang saya kira. Saya mengelompokkan berbagai hal menjadi 1.000 grup item, dan membiarkan kueri pengguna terhadap tabel baris 25K. Tapi pertanyaan saya berikutnya, akan melibatkan menggunakan hasil dari query itu untuk pergi ke tabel baris MASTER 25M dan menarik keluar, dan di situlah kinerja indeks gabungan benar-benar akan HIT].


contoh permintaan di bawah ini:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

MENJELASKAN hasil ANALISIS (saya tidak memasukkan indeks senyawa, dan dari kecepatan saya melihat saya tidak tahu jika saya perlu).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
Dr.YSG
sumber
2
Mohon berikan pertanyaan yang sebenarnya.
ypercubeᵀᴹ
Apakah "3 opsional" berarti bahwa kueri dapat memiliki 8 variasi yang berbeda (tergantung pada apakah 2,3,4 opsi diaktifkan atau tidak)?
ypercubeᵀᴹ
Ada 4 DAN komponen ke WHERE. Pada st_intersect diperlukan, yang lain mungkin ada di sana, atau mungkin tidak. Tetapi saya ingin menangani kasus di mana mereka semua hadir.
2
Saya memilih untuk memigrasi pertanyaan ke dba.se, ini adalah kueri yang kompleks dengan beberapa kondisi rentang.
ypercubeᵀᴹ
1
Tampilkan EXPLAIN ANALYZEuntuk kueri.
Craig Ringer

Jawaban:

4

Sebagai bagian dari pekerjaan saya, saya memelihara database PostgreSQL yang cukup besar (sekitar 120GB pada disk, beberapa tabel multi-juta-baris) dan telah mengumpulkan beberapa trik tentang cara mempercepat kueri. Pertama beberapa komentar pada asumsi Anda:

  1. Ya, pesanan itu penting, tetapi hanya yang pertama yang benar-benar berbeda, sisanya adalah indeks kelas dua.
  2. Saya tidak yakin ini akan selalu menggunakan keduanya, tebakan saya adalah bahwa perencana permintaan akan menggunakan # 1, kemudian melakukan sesuatu yang pintar dengan yang lain.
  3. Saya tidak punya pengalaman dengan GIST.
  4. Ya, tambahkan semua indeks terlebih dahulu, lihat apa yang paling sering digunakan dan apa yang memberikan kinerja terbaik.
  5. Saya sarankan Anda mencoba keduanya dan mengukur mana yang paling berhasil. Cobalah menulis ulang sql dengan subqueries yang berbeda, mungkin negara dan waktu dalam satu, kemudian bergabung dengan intersect-query. Saya belum melihat adanya masalah kinerja dengan klausa IN, selama IN-list tidak ribuan elemen. Dugaan saya adalah bahwa beberapa kueri yang berbeda secara khusus disetel tergantung pada kriteria input yang tersedia akan memberikan hasil terbaik.
  6. Saya akan menyarankan untuk tidak membuat indeks 4 arah. Coba buat satu dan kemudian periksa ukurannya, mereka bisa menjadi sangat besar. Dalam pengalaman saya, empat indeks 1-kunci hampir secepat indeks 4-arah tunggal. Trik yang berfungsi dengan baik untuk beberapa kueri tertentu adalah sebagian indeks, yaitu sesuatu seperti ini:

    CREATE INDEX ON table_x (key1, key2, key3) WHERE some_x_column = 'XXXX';

Saya telah membuat alias di file .psqlrc saya dengan kueri untuk membantu menemukan indeks apa yang akan ditambahkan atau dihapus. Jangan ragu untuk melihatnya di GitHub: .psql

Saya menggunakan: seq_scans dan: bigtable banyak, dan kemudian \ d table_name untuk mendapatkan detail tentang tabel. Jangan lupa mengatur ulang statistik setelah Anda melakukan beberapa perubahan, pilih pg_stat_reset ();

Claes Mogren
sumber
1
Ini adalah tips yang sangat bagus. Saya mengambil saran Anda, dan kemudian menggunakan ini untuk melakukan percobaan di meja yang jauh lebih besar yang kami pertahankan (43 juta baris). Hasilnya di: dba.stackexchange.com/questions/61084/…
Dr.YSG
1

Saya pikir hal yang paling mungkin membantu (jika ada) adalah menambahkan product_type sebagai kolom ke-2 ke indeks inti. Tetapi tanpa mengetahui berapa banyak baris yang cocok dengan masing-masing kondisi AND (dalam isolasi) untuk pertanyaan umum / bermasalah Anda, kami hanya bisa menebak.

Ketika saya mendekati ini, hal pertama yang saya lakukan adalah menjalankan kueri dalam bentuk yang disederhanakan di mana klausa WHERE hanya memiliki satu kondisi, masing-masing diambil secara bergantian, di bawah EXPLAIN ANALYZE. Lihatlah baris yang diestimasi dan baris aktual untuk masing-masing.

jjanes
sumber
lihat pembaruan saya di atas, tapi saya pikir Anda memberi saya petunjuk yang baik, pikirkan tentang memesan indeks yang memotong output baris paling cepat. Apakah itu benar?
Dr.YSG