Jadi saya memiliki tabel ini dengan 6,2 juta catatan dan saya harus melakukan permintaan pencarian dengan kesamaan untuk satu untuk kolom. Pertanyaannya bisa:
SELECT "lca_test".* FROM "lca_test"
WHERE (similarity(job_title, 'sales executive') > 0.6)
AND worksite_city = 'los angeles'
ORDER BY salary ASC LIMIT 50 OFFSET 0
Lebih banyak kondisi dapat ditambahkan di mana (tahun = X, worksite_state = N, status = 'bersertifikat', visa_class = Z).
Menjalankan beberapa pertanyaan itu bisa memakan waktu sangat lama, lebih dari 30 detik. Terkadang lebih dari satu menit.
EXPLAIN ANALYZE
kueri yang disebutkan sebelumnya memberi saya ini:
Limit (cost=0.43..42523.04 rows=50 width=254) (actual time=9070.268..33487.734 rows=2 loops=1) -> Index Scan using index_lca_test_on_salary on lca_test (cost=0.43..23922368.16 rows=28129 width=254) (actual time=9070.265..33487.727 rows=2 loops=1) >>>> Filter: (((worksite_city)::text = 'los angeles'::text) AND (similarity((job_title)::text, 'sales executive'::text) > 0.6::double precision)) >>>> Rows Removed by Filter: 6330130 Total runtime: 33487.802 ms Total runtime: 33487.802 ms
Saya tidak tahu bagaimana saya harus mengindeks kolom saya untuk membuatnya sangat cepat.
EDIT: Ini adalah versi postgres:
PostgreSQL 9.3.5 pada x86_64-unknown-linux-gnu, dikompilasi oleh gcc (Debian 4.7.2-5) 4.7.2, 64-bit
Berikut adalah definisi tabel:
Table "public.lca_test"
Column | Type | Modifiers | Storage | Stats target | Description
------------------------+-------------------+-------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('lca_test_id_seq'::regclass) | plain | |
raw_id | integer | | plain | |
year | integer | | plain | |
company_id | integer | | plain | |
visa_class | character varying | | extended | |
employement_start_date | character varying | | extended | |
employement_end_date | character varying | | extended | |
employer_name | character varying | | extended | |
employer_address1 | character varying | | extended | |
employer_address2 | character varying | | extended | |
employer_city | character varying | | extended | |
employer_state | character varying | | extended | |
employer_postal_code | character varying | | extended | |
employer_phone | character varying | | extended | |
employer_phone_ext | character varying | | extended | |
job_title | character varying | | extended | |
soc_code | character varying | | extended | |
naic_code | character varying | | extended | |
prevailing_wage | character varying | | extended | |
pw_unit_of_pay | character varying | | extended | |
wage_unit_of_pay | character varying | | extended | |
worksite_city | character varying | | extended | |
worksite_state | character varying | | extended | |
worksite_postal_code | character varying | | extended | |
total_workers | integer | | plain | |
case_status | character varying | | extended | |
case_no | character varying | | extended | |
salary | real | | plain | |
salary_max | real | | plain | |
prevailing_wage_second | real | | plain | |
lawyer_id | integer | | plain | |
citizenship | character varying | | extended | |
class_of_admission | character varying | | extended | |
Indexes:
"lca_test_pkey" PRIMARY KEY, btree (id)
"index_lca_test_on_id_and_salary" btree (id, salary)
"index_lca_test_on_id_and_salary_and_year" btree (id, salary, year)
"index_lca_test_on_id_and_salary_and_year_and_wage_unit_of_pay" btree (id, salary, year, wage_unit_of_pay)
"index_lca_test_on_id_and_visa_class" btree (id, visa_class)
"index_lca_test_on_id_and_worksite_state" btree (id, worksite_state)
"index_lca_test_on_lawyer_id" btree (lawyer_id)
"index_lca_test_on_lawyer_id_and_company_id" btree (lawyer_id, company_id)
"index_lca_test_on_raw_id_and_visa_and_pw_second" btree (raw_id, visa_class, prevailing_wage_second)
"index_lca_test_on_raw_id_and_visa_class" btree (raw_id, visa_class)
"index_lca_test_on_salary" btree (salary)
"index_lca_test_on_visa_class" btree (visa_class)
"index_lca_test_on_wage_unit_of_pay" btree (wage_unit_of_pay)
"index_lca_test_on_worksite_state" btree (worksite_state)
"index_lca_test_on_year_and_company_id" btree (year, company_id)
"index_lca_test_on_year_and_company_id_and_case_status" btree (year, company_id, case_status)
"index_lcas_job_title_trigram" gin (job_title gin_trgm_ops)
"lca_test_company_id" btree (company_id)
"lca_test_employer_name" btree (employer_name)
"lca_test_id" btree (id)
"lca_test_on_year_and_companyid_and_wage_unit_and_salary" btree (year, company_id, wage_unit_of_pay, salary)
Foreign-key constraints:
"fk_rails_8a90090fe0" FOREIGN KEY (lawyer_id) REFERENCES lawyers(id)
Has OIDs: no
worksite_city
.worksite_city
,worksite_state
,year
dan / ataustatus
Jawaban:
Anda lupa menyebutkan bahwa Anda menginstal modul tambahan
pg_trgm
, yang menyediakansimilarity()
fungsi.Operator kesamaan
%
Pertama-tama, apa pun yang Anda lakukan, gunakan operator kesamaan
%
alih-alih ekspresi(similarity(job_title, 'sales executive') > 0.6)
. Lebih murah. Dan dukungan indeks terikat pada operator di Postgres, bukan ke fungsi.Untuk mendapatkan kesamaan minimum yang diinginkan
0.6
, jalankan:Pengaturan tetap untuk sisa sesi Anda kecuali diatur ulang ke yang lain. Periksa dengan:
Ini agak canggung, tetapi bagus untuk kinerja.
Kasus sederhana
Jika Anda hanya menginginkan kecocokan terbaik dalam kolom
job_title
untuk 'eksekutif penjualan' string maka ini akan menjadi kasus sederhana pencarian "tetangga terdekat" dan dapat diselesaikan dengan indeks GiST menggunakan kelas operator trigramgist_trgm_ops
(tetapi tidak dengan indeks GIN) :Untuk juga memasukkan kondisi kesetaraan pada
worksite_city
Anda akan membutuhkan modul tambahanbtree_gist
. Jalankan (sekali per DB):Kemudian:
Pertanyaan:
<->
menjadi operator "jarak":Postgres juga dapat menggabungkan dua indeks terpisah, indeks btree biasa
worksite_city
, dan indeks GiST terpisahjob_title
, tetapi indeks multikolom harus tercepat - jika Anda menggabungkan dua kolom seperti ini dalam kueri secara teratur.Kasus Anda
Namun, kueri Anda diurutkan berdasarkan
salary
, bukan berdasarkan jarak / kesamaan, yang mengubah sifat permainan sepenuhnya. Sekarang kita dapat menggunakan indeks GIN dan GiST, dan GIN akan lebih cepat (bahkan lebih lagi di Postgres 9.4 yang sebagian besar telah meningkatkan indeks GIN - petunjuk!)Kisah serupa untuk pemeriksaan kesetaraan tambahan tentang
worksite_city
: pasang modul tambahanbtree_gin
. Jalankan (sekali per DB):Kemudian:
Pertanyaan:
Sekali lagi, ini juga harus bekerja (kurang efisien) dengan indeks sederhana yang sudah Anda miliki (
"index_lcas_job_title_trigram"
), mungkin dalam kombinasi dengan indeks lain. Solusi terbaik tergantung pada gambar lengkap.Selain itu
Anda memiliki banyak indeks. Apakah Anda yakin mereka semua digunakan dan membayar biaya perawatannya?
Anda memiliki beberapa tipe data yang meragukan:
Sepertinya itu seharusnya
date
. DllJawaban terkait:
sumber
"index_lcas_job_title_trigram" gin (job_title gin_trgm_ops)
membaca di suatu tempat bahwa gin lebih cepat daripada inti. Benarkah?similarity
sama sekali, jadi untuk tujuan itu tidak lebih cepat.btree_gin
. Tetapi kemudian dalam pembuatan indeks Anda mengatakan untuk menjalankan:CREATE INDEX lcas_trgm_gin_idx ON lcas USING gist (worksite_city, job_title gist_trgm_ops);
Hanya salah ketik?