Dizin maks. Satır boyutu hatası


12

Bir arraysütun için üst sınır var mı ?

Dizi alanına eklerken bu hatayı alıyorum -

PG::Error: ERROR:  index row size 3480 exceeds maximum 2712 for index "ix_data"

İşte benim masa tanımı -

create table test_array(id varchar(50), data text[]);

ALTER TABLE test_array ADD PRIMARY KEY (id);

CREATE INDEX ix_data ON test_array USING GIN (data);

Bazı aramalar yapıyorum beri dizi alanında bir dizin gerekir.


O olabilir databu 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.
Erwin Brandstetter

user310525, orada bir hesap oluşturmak ve bir moderatörün taşınması için işaretlemek istiyorsanız, dba.se'de bunun daha iyi olacağını düşünerek Erwin'in önerisini ikinci olarak isterim?
Jack diyor ki topanswers.xyz

Yanıtlar:


14

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 datagö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

serialBirincil 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 datadaha sonra tür olacaktır int[]. Masayı yeniden adlandırdım ve örneğinizdeki datauğursuzluktan kurtuldum varchar(50):

CREATE TEMP TABLE data(
  data_id serial PRIMARY KEY
, data int[]
);

İçindeki her dizi öğesi dataa 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_idtablodan 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 intarrayEk işleçler ve işleç sınıfları sağlayan .

Sqlfiddle üzerinde tamamen işlevsel canlı demo.


2

Hata, alanla ix_datadeğil dizinle ilgilidir text[]. Söz konusu dizin türündeki bir satırın maksimum boyutu baytlarla sınırlıdır 2712. Dizininizi bırakır ve eki tekrar denerseniz, sizin için çalışması gerekir. Daha büyük bir alanı dizine eklemeniz gerekiyorsa, postgres'in tam metin dizine ekleme özelliklerine bakmak isteyebilirsiniz.


2

Bunu bir PostGIS coğrafya sütununda alıyordum. Çünkü dizini yanlışlıkla yanlış oluşturdum. Bu tür dizinler oluştururken USING GIST parametresini eklemelisiniz.


Teşekkür ederim - hepsi bu kadar! Vay, şimdiye kadar getirildi. Bana saatler kurtarabilirdi. Özellikle GiST'nin varsayılan olarak kullanıldığını düşündüğümden beri yanılmışım ve b-ağacı kullanmaya çalışıyor.
Jonas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.