tl; dr Bạn cần thêm chỉ mục trên item_id
. "Ma thuật đen" của việc lập chỉ mục Postgres được đề cập trong 11. Chỉ mục
.
Bạn có một chỉ mục tổng hợp trên (topic_id, item_id)
và thứ tự cột là quan trọng. Postgres có thể sử dụng điều này để lập chỉ mục các truy vấn trên topic_id
, truy vấn trên cả topic_id
và item_id
, nhưng không (hoặc kém hiệu quả hơn) item_id
một mình.
Từ 11.3. Chỉ mục nhiều cột ...
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
Điều này là do chỉ mục tổng hợp như (topic_id, item_id)
lưu trữ ID chủ đề trước, sau đó là ID mặt hàng cũng có ID chủ đề đó. Để tra cứu ID mục một cách hiệu quả trong chỉ mục này, trước tiên Postgres phải thu hẹp tìm kiếm bằng ID chủ đề.
Postgres can đảo ngược một chỉ mục nếu nó cho rằng nó đáng để nỗ lực. Nếu có một số lượng nhỏ các ID chủ đề có thể có và một số lượng lớn các ID chỉ mục có thể có, nó sẽ tìm kiếm ID chỉ mục trong mỗi ID chủ đề.
Ví dụ:giả sử bạn có 10 ID chủ đề và 1000 ID mặt hàng khả thi và chỉ mục của bạn (topic_id, index_id)
. Điều này giống như có 10 nhóm ID chủ đề được dán nhãn rõ ràng, mỗi nhóm có 1000 nhóm ID mục được dán nhãn rõ ràng bên trong. Để truy cập nhóm ID mục, nó phải nhìn vào bên trong mỗi nhóm ID chủ đề. Để sử dụng chỉ mục này trên where item_id = 23
Postgres phải tìm kiếm từng nhóm trong số 10 nhóm ID chủ đề cho tất cả các nhóm có ID mục 23.
Nhưng nếu bạn có 1000 ID chủ đề và 10 ID mặt hàng khả thi, Postgres sẽ phải tìm kiếm nhóm 1000 ID chủ đề. Nhiều khả năng thay vào đó nó sẽ quét toàn bộ bảng. Trong trường hợp này, bạn muốn đảo ngược chỉ mục của mình và đặt nó thành (item_id, topic_id)
.
Điều này phụ thuộc nhiều vào việc thống kê bảng tốt, có nghĩa là đảm bảo autovacuum hoạt động bình thường.
Vì vậy, bạn có thể sử dụng một chỉ mục duy nhất cho hai cột, nếu một cột có ít biến động hơn cột khác.
Postgres cũng có thể sử dụng nhiều chỉ mục nếu nó cho rằng nó sẽ làm cho truy vấn chạy nhanh hơn
. Ví dụ:nếu bạn có một chỉ mục trên topic_id
và một chỉ mục trên item_id
, nó có thể sử dụng cả hai chỉ mục và kết hợp các kết quả. Ví dụ:where topic_id = 23 or item_id = 42
có thể sử dụng chỉ mục topic_id để tìm kiếm ID chủ đề 23 và chỉ mục item_id để tìm kiếm ID mặt hàng 42, sau đó kết hợp các kết quả.
Điều này thường chậm hơn so với việc có (topic_id, item_id)
mục lục. Nó cũng có thể chậm hơn so với sử dụng một chỉ mục, vì vậy đừng ngạc nhiên nếu Postgres quyết định không sử dụng nhiều chỉ mục.
Nói chung, đối với chỉ mục b-tree, khi bạn có hai cột, bạn có thể có ba kết hợp.
- a + b
- a
- b
Và bạn cần hai chỉ mục.
- (a, b) - a và a + b
- (b) - b
(a, b)
bao gồm cả tìm kiếm a và a + b. (b)
bao gồm tìm kiếm b
.
Khi bạn có ba cột, bạn có bảy kết hợp khả thi.
- a + b + c
- a + b
- a + c
- a
- b + c
- b
- c
Nhưng bạn chỉ cần ba chỉ mục.
- (a, b, c) - a, a + b, a + b + c
- (b, c) - b, b + c
- (c, a) - c, c + a
Tuy nhiên, bạn có thể thực sự muốn tránh có một chỉ mục trên ba cột. Nó thường chậm hơn . Điều bạn thực sự muốn là cái này.
- (a, b)
- (b, c)
- (c, a)
Đọc từ một chỉ mục chậm hơn đọc từ bảng. Bạn muốn các chỉ mục của mình giảm số hàng phải đọc, nhưng bạn không muốn Postgres phải quét chỉ mục nhiều hơn mức cần thiết.