PostgreSQL sebenarnya mendukung indeks GIN pada kolom array. Sayangnya, sepertinya tidak dapat digunakan untuk NOT ARRAY[...] <@ indexed_col
, dan GIN
indeks tidak cocok untuk tabel yang sering diperbarui.
Demo:
CREATE TABLE arrtable (id integer primary key, array_column integer[]);
INSERT INTO arrtable(1, ARRAY[1,2,3,4]);
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
-- Use the following *only* for testing whether Pg can use an index
-- Do not use it in production.
SET enable_seqscan = off;
explain (buffers, analyze) select count(id)
from arrtable
where not (ARRAY[1] <@ arrtable.array_column);
Sayangnya, ini menunjukkan bahwa seperti yang tertulis, kami tidak dapat menggunakan file index. Jika Anda tidak meniadakan kondisi itu dapat digunakan, sehingga Anda dapat mencari dan menghitung baris yang lakukan mengandung elemen pencarian (dengan menghapus NOT
).
Anda dapat menggunakan indeks untuk menghitung entri yang lakukan berisi nilai target, lalu kurangi hasil itu dari hitungan semua entri. Sejak count
ing semua baris dalam tabel cukup lambat di PostgreSQL (9.1 dan lebih tua) dan memerlukan pemindaian berurutan ini sebenarnya akan lebih lambat dari permintaan Anda saat ini. Ada kemungkinan bahwa pada 9.2 pemindaian hanya indeks dapat digunakan untuk menghitung baris jika Anda memiliki indeks b-tree pada id
, dalam hal ini mungkin sebenarnya baik-baik saja:
SELECT (
SELECT count(id) FROM arrtable
) - (
SELECT count(id) FROM arrtable
WHERE (ARRAY[1] <@ arrtable.array_column)
);
Ini dijamin berkinerja lebih buruk daripada versi asli Anda untuk Pg 9.1 dan di bawahnya, karena selain seqscan asli Anda memerlukannya juga membutuhkan pemindaian indeks GIN. Saya sekarang telah menguji ini pada 9.2 dan tampaknya menggunakan indeks untuk penghitungan, jadi perlu ditelusuri untuk 9.2. Dengan beberapa data dummy yang tidak terlalu sepele:
drop index arrtable_arraycolumn_gin_arr_idx ;
truncate table arrtable;
insert into arrtable (id, array_column)
select s, ARRAY[1,2,s,s*2,s*3,s/2,s/4] FROM generate_series(1,1000000) s;
CREATE INDEX arrtable_arraycolumn_gin_arr_idx
ON arrtable USING GIN(array_column);
Perhatikan bahwa indeks GIN seperti ini akan memperlambat pembaruan BANYAK, dan cukup lambat untuk dibuat. Ini tidak cocok untuk tabel yang sering diperbarui - seperti tabel Anda.
Lebih buruk lagi, kueri yang menggunakan indeks ini membutuhkan waktu hingga dua kali lebih lama dari kueri asli Anda dan paling lama setengahnya pada kumpulan data yang sama. Ini terburuk untuk kasus di mana indeks tidak terlalu selektif seperti ARRAY[1]
- 4s vs 2s untuk kueri asli. Di mana indeks sangat selektif (yaitu:tidak banyak kecocokan, seperti ARRAY[199]
) ini berjalan dalam waktu sekitar 1,2 detik vs 3 detik yang asli. Indeks ini sama sekali tidak berharga untuk kueri ini.
Pelajaran di sini? Terkadang, jawaban yang tepat adalah dengan melakukan pemindaian berurutan.
Karena itu tidak akan berhasil untuk rasio klik Anda, pertahankan tampilan terwujud dengan pemicu seperti yang disarankan @debenhur, atau coba balikkan larik menjadi daftar parameter yang tidak masuki. miliki sehingga Anda dapat menggunakan indeks GiST seperti yang disarankan @maniek.