Masalah
Berikut adalah kasus yang sangat mirip yang dibahas di pgsql.general . Ini tentang batasan dalam indeks b-tree, tapi itu semua sama karena indeks GIN menggunakan indeks b-tree untuk kunci secara internal dan oleh karena itu mengalami batasan yang sama untuk ukuran kunci (bukan ukuran item dalam b-tree polos indeks).
Saya mengutip manual tentang implementasi indeks GIN :
Secara internal, indeks GIN berisi indeks B-tree yang dibangun di atas kunci, di mana setiap kunci adalah elemen dari satu atau lebih item yang diindeks
Either way, setidaknya satu elemen array di kolom Anda data
terlalu besar untuk diindeks. Jika ini hanya nilai aneh tunggal atau semacam kecelakaan, Anda mungkin dapat memotong nilainya dan dilakukan dengan itu.
Untuk keperluan demo berikut, saya akan menganggap sebaliknya: banyak nilai teks panjang dalam array.
Solusi sederhana
Anda bisa mengganti elemen dalam array Anda data
dengan nilai hash yang sesuai . Dan mengirim nilai pencarian melalui fungsi hash yang sama. Tentu saja, Anda mungkin ingin menyimpan dokumen asli Anda di suatu tempat. Dengan itu, kami hampir tiba di varian kedua saya ...
Solusi canggih
Anda bisa membuat tabel pencarian untuk elemen array dengan serial
kolom sebagai pengganti kunci primer (secara efektif jenis nilai hash radikal) - yang lebih menarik jika nilai elemen yang terlibat tidak unik:
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
Karena kita ingin mencari elem
, kita menambahkan indeks - tapi sebuah indeks pada ekspresi saat ini, dengan hanya 10 karakter pertama dari teks yang panjang. Itu seharusnya cukup dalam kebanyakan kasus untuk mempersempit pencarian ke satu atau beberapa hits. Sesuaikan ukuran dengan distribusi data Anda. Atau gunakan fungsi hash yang lebih canggih.
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
Kolom Anda data
kemudian akan bertipe int[]
. Saya mengganti nama tabel data
dan menyingkirkan yang tidak menyenangkan yang varchar(50)
Anda miliki dalam contoh Anda:
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
Setiap elemen array data
mengacu pada a elem.elem_id
. Pada titik ini, Anda dapat mempertimbangkan untuk mengganti kolom array dengan tabel n: m, sehingga menormalkan skema Anda dan memungkinkan Postgres untuk menegakkan integritas referensial. Pengindeksan dan penanganan umum menjadi lebih mudah ...
Namun, untuk alasan kinerja, int[]
kolom dalam kombinasi dengan indeks GIN mungkin lebih unggul. Ukuran penyimpanan jauh lebih kecil. Dalam hal ini kita membutuhkan indeks GIN:
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
Sekarang, setiap kunci indeks GIN (= elemen array) adalah integer
bukan gondrong text
. Indeks akan lebih kecil dengan beberapa urutan besarnya, pencarian akan lebih cepat.
The downside: sebelum Anda benar-benar dapat melakukan pencarian, Anda harus melihat elem_id
dari tabel elem
. Menggunakan indeks fungsional saya yang baru diperkenalkan elem_elem_left10_idx
, ini juga akan jauh lebih cepat.
Anda dapat melakukan semuanya dalam satu permintaan sederhana :
SELECT d.*, e.*
FROM elem e
JOIN data d ON ARRAY[e.elem_id] <@ d.data
WHERE left(e.elem, 10) = left('word1234word', 10) -- match index condition
AND e.elem = 'word1234word'; -- need to recheck, functional index is lossy
Anda mungkin tertarik pada ekstensi intarray
, yang memasok operator tambahan dan kelas operator.
data
berisi daftar tag seperti ditunjukkan dalam posting blog terkait ini oleh Scott Snyder ? Jika itu masalahnya, saya mungkin punya solusi yang lebih baik untuk Anda.