2016-03-18 14 views
14

Sử dụng Postgres 9.4, tôi muốn tạo chỉ mục trên cột json sẽ được sử dụng khi tìm kiếm trên các khóa cụ thể trong cột.Chỉ mục PostgreSQL trên JSON

Ví dụ tôi có một bảng 'nông trại' với một cột json 'động vật'.

Cột động vật có đối tượng json của định dạng chung:

'{"cow": 2, "chicken": 11, "horse": 3}' 

Tôi đã thử một số chỉ số (riêng):

(1) create INDEX animal_index ON farm ((animal ->> 'cow')); 
(2) create INDEX animal_index ON farm using gin ((animal ->> 'cow')); 
(3) create INDEX animal_index ON farm using gist ((animal ->> 'cow')); 

Tôi muốn chạy các truy vấn như:

SELECT * FROM farm WHERE (animal ->> 'cow') > 3; 

và yêu cầu truy vấn đó sử dụng chỉ mục.

Khi tôi chạy truy vấn này:

SELECT * FROM farm WHERE (animal ->> 'cow') is null; 

thì (1) chỉ số hoạt động, nhưng tôi không thể nhận được bất kỳ của các chỉ số để làm việc cho sự bất bình đẳng.

là một chỉ số như vậy có thể?

Bảng trang trại chỉ chứa ~ 5000 trang trại, nhưng một số trang trại chứa 100 con vật và truy vấn chỉ mất quá nhiều thời gian cho trường hợp sử dụng của tôi. Một chỉ mục như thế này là phương pháp duy nhất tôi có thể nghĩ đến để tăng tốc truy vấn này, nhưng có lẽ có một tùy chọn khác.

Trả lời

29

hai chỉ số khác của bạn sẽ không hoạt động đơn giản chỉ vì lợi nhuận ->> operatortext, trong khi bạn rõ ràng là có các lớp học hành jsonb gin trong tâm trí. Lưu ý rằng bạn chỉ đề cập đến json, nhưng bạn thực sự cần jsonb để có khả năng lập chỉ mục nâng cao.

Xây dựng chiến lược lập chỉ mục tốt nhất, bạn phải xác định chặt chẽ hơn mà các truy vấn để trang trải. Bạn chỉ quan tâm đến bò? Hoặc tất cả động vật/tất cả các thẻ? Những nhà khai thác nào có thể? Tài liệu JSON của bạn có bao gồm các khóa không phải là động vật không? Làm gì với những thứ đó? Bạn có muốn bao gồm các hàng trong chỉ mục mà bò (hoặc bất kỳ thứ gì) không hiển thị trong tài liệu JSON không?

Giả sử:

  • Chúng tôi chỉ quan tâm đến con bò ở cấp đầu tiên của tổ.
  • Giá trị luôn là integer hợp lệ.
  • Chúng tôi không quan tâm đến hàng không có bò.

Tôi đề xuất chỉ số btree chức năng, giống như bạn đã có, nhưng truyền giá trị thành số nguyên. Tôi không cho rằng bạn muốn so sánh được đánh giá là text (trong đó '2' lớn hơn '1111').

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)); -- ! 

Cần thêm dấu ngoặc đơn để làm cho cú pháp cho biểu thức chỉ mục không rõ ràng.

Sử dụng cùng một biểu thức trong các truy vấn của bạn để làm cho Postgres nhận ra chỉ số được áp dụng:

SELECT * FROM farm WHERE (animal ->> 'cow')::int > 3; 

Nếu bạn cần một jsonb chỉ số chung chung hơn, hãy xem xét:

Đối với số đã biết, tĩnh, tầm thường số động vật (như yo u nhận xét), tôi đề nghị chỉ số phần như:

CREATE INDEX animal_index ON farm (((animal ->> 'cow')::int)) 
WHERE (animal ->> 'cow') IS NOT NULL; 

CREATE INDEX animal_index ON farm (((animal ->> 'chicken')::int)) 
WHERE (animal ->> 'chicken') IS NOT NULL; 

vv

Bạn có thể phải thêm điều kiện chỉ số để truy vấn:

SELECT * FROM farm 
WHERE (animal ->> 'cow')::int > 3 
AND (animal ->> 'cow') IS NOT NULL; 

Có thể có vẻ hơi thừa, nhưng có thể cần thiết . Thử nghiệm với ANALYZE!

+0

Cảm ơn bạn! Câu trả lời tuyệt vời. Tôi chỉ quan tâm đến cấp độ đầu tiên. Giá trị luôn là số nguyên. Tuy nhiên tôi quan tâm đến một số động vật khác. Liệu nó có ý nghĩa để đơn giản sao chép chỉ mục này cho từng con vật mà tôi quan tâm? – lnhubbell

+0

@lnhubbell: Dành cho * số lượng động vật được biết, tĩnh, tầm thường * này nên là giải pháp đơn giản và hiệu quả nhất. Tôi rõ ràng sẽ làm cho chúng một phần chỉ mục, mặc dù. Xem phụ lục ở trên. –

Các vấn đề liên quan