Sorun
İşte pgsql.general üzerinde tartışılan çok benzer bir durum . Bir b-ağacı dizinindeki sınırlama hakkındadır, ancak hepsi aynıdır, çünkü bir GIN endeksi dahili olarak anahtarlar için b-ağacı dizini kullanır ve bu nedenle anahtar boyutu için aynı sınırlamaya girer ( düz bir b ağacındaki öğe boyutu yerine) endeksi).
Ben alıntı CİN endeksi uygulaması hakkında kılavuzu :
Dahili olarak, bir GIN dizini, anahtarlar üzerinde oluşturulmuş bir B-ağacı dizini içerir; burada her anahtar, bir veya daha fazla dizinlenmiş öğenin bir öğesidir
Her iki durumda da, sütununuzdaki en az bir dizi öğesidata
dizine eklenemeyecek kadar büyük. Bu sadece tekil bir ucube değeri veya bir tür kaza ise, değeri kısaltabilir ve onunla yapılabilir.
Aşağıdaki demonun amacı için başka türlü olduğunu varsayacağım: dizideki birçok uzun metin değeri.
Basit çözüm
Eğer dizideki öğeleri yerini alabilir data
göre olan karma değerlerini . Ve aynı hash fonksiyonu ile arama değerleri gönderin. Elbette, orijinallerinizi ek olarak bir yerde saklamak istersiniz. Bununla neredeyse ikinci varyantıma ulaşıyoruz ...
Gelişmiş çözüm
serial
Birincil anahtar olarak sütunu (etkili bir şekilde radikal bir karma değeri türü) içeren dizi öğeleri için bir arama tablosu oluşturabilirsiniz; bu, ilgili öğe değerleri benzersiz değilse daha da ilginçtir:
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
Aramak istediğimizden elem
, bu sefer bir ifadeye bir dizin ekliyoruz - ancak uzun metnin yalnızca ilk 10 karakterini içeren bir dizin . Çoğu durumda bir aramayı bir veya birkaç isabetle daraltmak için yeterli olmalıdır. Boyutu veri dağıtımınıza uyarlayın. Veya daha karmaşık bir karma işlevi kullanın.
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
Sütununuz data
daha sonra tür olacaktır int[]
. Masayı yeniden adlandırdım ve örneğinizdeki data
uğursuzluktan kurtuldum varchar(50)
:
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
İçindeki her dizi öğesi data
a elem.elem_id
. Bu noktada, dizi sütununu n: m tablosuyla değiştirmeyi, böylece şemanızı normalleştirmeyi ve Postgres'in başvuru bütünlüğünü zorunlu kılmalarını sağlayabilirsiniz. Endeksleme ve genel kullanım kolaylaşır ...
Bununla birlikte, performans nedenlerinden ötürü, int[]
bir GIN endeksi ile birlikte sütun daha iyi olabilir. Depolama boyutu çok daha küçük. Bu durumda GIN dizinine ihtiyacımız var:
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
Şimdi, her anahtar GIN endeksinin (= dizi elemanı)integer
, bir longish yerine text
. Endeks, birkaç büyüklük sırasına göre daha küçük olacak, aramalar çok daha hızlı olacaktır.
Dezavantajı: bir arama yapmadan önce elem_id
tablodan bakmanız gerekir elem
. Yeni tanıtılan işlevsel dizinimi kullanarak elem_elem_left10_idx
, bu da çok daha hızlı olacaktır.
Bunu yapabilirsin basit bir sorguda yapabilirsiniz :
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
Uzantıyla ilgileniyor olabilirsiniz intarray
Ek işleçler ve işleç sınıfları sağlayan .
data
bu gösterilmiştir gibi bir etiket listesi içeren Scott Snyder tarafından ilgili blog post ? Eğer durum buysa, sizin için daha iyi bir çözümüm olabilir.