Chỉ số lỗi kích thước hàng tối đa


12

Có một giới hạn trên cho một arraycột?

Tôi gặp lỗi này khi chèn vào trường mảng -

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

Đây là định nghĩa bảng của tôi -

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);

Tôi cần một chỉ mục trên trường mảng, vì tôi đang thực hiện một số tra cứu về nó.


Có thể nó datachứa một danh sách các thẻ như được trình bày trong bài đăng trên blog liên quan này của Scott Snyder ? Nếu đó là trường hợp, tôi có thể có một giải pháp tốt hơn cho bạn.
Erwin Brandstetter

user310525, tôi muốn đề xuất thứ hai của Erwin rằng điều này sẽ tốt hơn trên dba.se, nếu bạn sẵn sàng tạo một tài khoản ở đó và gắn cờ cho người điều hành di chuyển?
Jack nói hãy thử topanswers.xyz

Câu trả lời:


14

Vấn đề

Đây là một trường hợp rất giống nhau được thảo luận trên pssql.general . Đó là về giới hạn trong chỉ mục cây b, nhưng tất cả đều giống nhau vì chỉ số GIN sử dụng chỉ mục cây b cho các khóa bên trong và do đó chạy vào cùng giới hạn cho kích thước khóa (thay vì kích thước mục trong cây b đơn giản mục lục).

Tôi trích dẫn hướng dẫn thực hiện chỉ số GIN :

Trong nội bộ, một chỉ mục GIN chứa chỉ mục cây B được xây dựng trên các khóa, trong đó mỗi khóa là một thành phần của một hoặc nhiều mục được lập chỉ mục

Dù bằng cách nào, ít nhất một phần tử mảng trong cột của bạn dataquá lớn để được lập chỉ mục. Nếu đây chỉ là một giá trị kỳ dị hoặc một loại tai nạn nào đó, bạn có thể cắt bớt giá trị và được thực hiện với nó.

Với mục đích của bản demo sau, tôi sẽ giả sử khác: rất nhiều giá trị văn bản dài trong mảng.

Giải pháp đơn giản

Bạn có thể thay thế các phần tử trong mảng của bạn databằng các giá trị băm theo . Và gửi các giá trị tra cứu thông qua chức năng băm tương tự. Tất nhiên, bạn có thể muốn lưu trữ bản gốc của bạn ngoài một nơi nào đó. Cùng với đó, chúng tôi gần như đến biến thể thứ hai của mình ...

Giải pháp tiên tiến

Bạn có thể tạo bảng tra cứu cho các phần tử mảng với một serialcột là khóa chính thay thế (thực sự là một loại giá trị băm triệt để) - điều này thú vị hơn nếu các giá trị phần tử liên quan không phải là duy nhất:

CREATE TABLE elem (
  elem_id serial NOT NULL PRIMARY KEY
, elem    text UNIQUE NOT NULL
);

Kể từ khi chúng tôi muốn tìm kiếm elem, chúng tôi thêm một chỉ số - nhưng một chỉ mục trên một biểu thời gian này, chỉ với 10 ký tự đầu tiên của văn bản dài. Điều đó là đủ trong hầu hết các trường hợp để thu hẹp tìm kiếm xuống một hoặc một vài lần truy cập. Điều chỉnh kích thước để phân phối dữ liệu của bạn. Hoặc sử dụng hàm băm tinh vi hơn.

CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));

Cột của bạn datasau đó sẽ là loại int[]. Tôi đã đổi tên bảng thành datavà loại bỏ những điều đáng ngại varchar(50)trong ví dụ của bạn:

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

Mỗi phần tử mảng trong datatham chiếu đến a elem.elem_id. Tại thời điểm này, bạn có thể xem xét thay thế cột mảng bằng bảng n: m, từ đó bình thường hóa lược đồ của bạn và cho phép Postgres thực thi tính toàn vẹn tham chiếu. Lập chỉ mục và xử lý chung trở nên dễ dàng hơn ...

Tuy nhiên, vì lý do hiệu suất, int[]cột kết hợp với chỉ số GIN có thể vượt trội. Kích thước lưu trữ nhỏ hơn rất nhiều . Trong trường hợp này, chúng ta cần chỉ số GIN:

CREATE INDEX data_data_gin_idx ON data USING GIN (data);

Bây giờ, mỗi khóa của chỉ mục GIN (= phần tử mảng) là một integerthay vì dài text. Chỉ số sẽ nhỏ hơn theo một số bậc độ lớn, do đó các tìm kiếm sẽ nhanh hơn nhiều .

Nhược điểm: trước khi bạn thực sự có thể thực hiện tìm kiếm, bạn phải tra cứu elem_idtừ bảng elem. Sử dụng chỉ số chức năng mới được giới thiệu của tôi elem_elem_left10_idx, điều này cũng sẽ nhanh hơn nhiều.

Bạn có thể làm tất cả trong một truy vấn đơn giản :

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

Bạn có thể quan tâm đến phần mở rộng intarray, cung cấp các toán tử bổ sung và các lớp toán tử.

Bản demo trực tiếp đầy đủ chức năng trên sqlfiddle.


2

Lỗi là với chỉ mục ix_data, không phải text[]trường. Kích thước tối đa cho một hàng trong loại chỉ mục cụ thể đó được giới hạn theo 2712byte. Nếu bạn bỏ chỉ mục của mình và thử chèn lại, nó sẽ hoạt động cho bạn. Nếu bạn cần lập chỉ mục một trường lớn hơn, bạn có thể muốn xem xét các tính năng lập chỉ mục văn bản đầy đủ của postgres.


2

Tôi đã nhận được điều này trên một cột địa lý PostGIS. Đó là bởi vì tôi vô tình tạo ra chỉ mục không chính xác. Bạn nên bao gồm tham số SỬ DỤNG GIST khi tạo các chỉ mục như vậy.


Cảm ơn bạn - đó là nó! Wow, cho đến nay lấy. Có thể đã giúp tôi tiết kiệm hàng giờ. Đặc biệt là vì tôi nghĩ GiST được sử dụng theo mặc định nhưng tôi đã nhầm và nó cố gắng sử dụng b-tree.
Jonas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.