PostgreSQL có thể sử dụng null trong các chỉ mục của nó không?


10

Tôi đã đọc cuốn sách này nói rằng

Cơ sở dữ liệu giả định rằng Indexed_Col IS KHÔNG NULL bao phủ phạm vi quá lớn sẽ không hữu ích, vì vậy cơ sở dữ liệu sẽ không hướng đến một chỉ mục từ điều kiện này.

Tôi nhận ra rằng cuốn sách đã hơn 10 năm tuổi, nhưng nó đã được chứng minh khá hữu ích - Sử dụng các hướng dẫn lượm lặt được từ các trang của nó, tôi đã tăng một truy vấn lên gấp 10 lần.

Hơn nữa, khi chạy EXPLAIN ANALYZEtrên một SELECTtruy vấn, tôi thấy rằng không có chỉ mục nào của tôi đang được sử dụng, ngay cả khi tất cả các quyền, chúng đều phải như vậy.

Vì vậy, câu hỏi của tôi là:

Giả sử có một bảng có một cột, có định nghĩa cột bao gồm "KHÔNG NULL" và chỉ mục tồn tại bao gồm cột này, liệu chỉ mục này có được sử dụng trong truy vấn của bảng đó trong đó các cột là một phần của truy vấn không?

Giống:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Câu trả lời:


9

PostgreSQL chắc chắn có thể sử dụng một chỉ mục cho IS NOT NULL. Tôi cũng không thấy bất kỳ giả định kế hoạch truy vấn nào về tình trạng đó.

Nếu phần null cho cột ( pg_statistic.stanullfrac) đủ thấp để đề xuất rằng chỉ mục có thể chọn lọc hữu ích cho truy vấn, PostgreQuery sẽ sử dụng một chỉ mục.

Tôi không thể hiểu bạn đang cố nói gì với:

Nếu điều này là chính xác, tôi có hiểu rằng một chỉ mục trên một cột được xác định là "KHÔNG NULL" không được sử dụng trong truy vấn sử dụng cột đó không?

Chắc chắn một chỉ mục sẽ không được sử dụng cho một IS NOT NULLđiều kiện trên một NOT NULLcột. Nó luôn luôn khớp 100% các hàng, vì vậy một seqscan sẽ luôn luôn nhanh hơn nhiều.

PostgreQuery sẽ không sử dụng chỉ mục nếu chỉ mục không lọc ra một tỷ lệ lớn các hàng cho truy vấn. Ngoại lệ có khả năng duy nhất là khi bạn yêu cầu một tập hợp các cột được bao phủ bởi một chỉ mục duy nhất, theo thứ tự khớp với chỉ mục của chỉ mục. PostgreSQL có thể thực hiện quét chỉ mục sau đó. Ví dụ: nếu có một chỉ mục trên t(a, b, c)và bạn:

select a, b FROM t ORDER BY a, b, c;

PostgreSQL có thể sử dụng chỉ mục của bạn, mặc dù không có hàng nào được lọc, bởi vì nó chỉ phải đọc chỉ mục và có thể bỏ qua việc đọc heap, tránh thực hiện sắp xếp, v.v.


Điều này hoàn toàn đúng với PG 9.0
eradman

1
Và ngay cả trên một cột không thể, một truy vấn có điều kiện WHERE column IS NOT NULLcó thể không sử dụng chỉ mục bởi vì, như cuốn sách nói: "bao phủ phạm vi quá lớn sẽ không hữu ích". Nếu 90% giá trị không phải là null, một seqscan cũng có thể sẽ nhanh hơn.
ypercubeᵀᴹ

Chính xác. Nó có thể, nhưng chỉ khi một phần lớn của bảng là null. Thường thì trong trường hợp này, một phần chỉ số là một lựa chọn tốt hơn.
Craig Ringer

Đúng. Tôi đã cố gắng nói rằng (theo tôi hiểu) phần "bao phủ phạm vi quá lớn" đề cập đến chỉ số nhưng liên quan đến điều kiện cụ thể và không phải là chỉ số nói chung.
ypercubeᵀᴹ

2
@FquilFolder Heh, có quá nhiều tiêu cực ở đây. PostgreQuery sẽ không sử dụng một chỉ mục trên một NOT NULLcột cho một IS NOT NULLtruy vấn trừ khi chỉ mục đó cũng hữu ích cho các phần khác của WHEREmệnh đề, tham gia các bộ lọc, v.v. hoặc có thể sử dụng để quét chỉ mục theo thứ tự. Nói cách khác, nó sẽ hoàn toàn bỏ qua phần dư thừa IS NOT NULLtrên NOT NULLcột và thực hiện các lựa chọn sử dụng chỉ mục dựa trên các chi tiết khác. (Xem chỉnh sửa, quét lại chỉ mục).
Craig Ringer

2

Ngoài câu trả lời thấu đáo của Craig, tôi muốn thêm rằng bìa của cuốn sách mà bạn tham khảo nói:

Bao gồm máy chủ Oracle, DB2 & SQL

Vì vậy, tôi không tin tưởng nó sẽ là một nguồn tư vấn tuyệt vời về PostgreSQL nói riêng. Mỗi RDBMS có thể khác nhau đáng ngạc nhiên!

Tôi hơi bối rối về câu hỏi ban đầu của bạn, nhưng đây là một ví dụ cho thấy phần của cuốn sách không chính xác 100%. Để tránh nhầm lẫn thêm, đây là toàn bộ đoạn có liên quan, bạn có thể xem nó trong Tìm kiếm Sách của Google .

Cơ sở dữ liệu giả định rằng Indexed_Col IS KHÔNG NULL bao phủ phạm vi quá lớn sẽ không hữu ích, vì vậy cơ sở dữ liệu sẽ không hướng đến một chỉ mục từ điều kiện này. Trong các trường hợp hiếm hoi, việc có bất kỳ giá trị không phải nào là rất hiếm khi quét phạm vi chỉ mục trên tất cả các giá trị không có giá trị có thể có lợi. Trong các trường hợp như vậy, nếu bạn có thể tìm ra giới hạn dưới hoặc trên an toàn cho phạm vi của tất cả các giá trị có thể, bạn có thể kích hoạt quét phạm vi với một điều kiện như positive_ID_Column> -1 hoặc Date_Column> TO_DATE ('0001/01/01' , 'YYYY / MM / DD').

Postgres thực sự có thể (trong trường hợp giả định sau) sử dụng một chỉ mục để đáp ứng IS NOT NULLcác truy vấn mà không cần thêm các khoảng quét quét phạm vi như đề xuất Positive_ID_Column > -1. Xem các nhận xét về câu hỏi của Craig để biết lý do tại sao Postgres chọn chỉ mục này trong trường hợp cụ thể này và lưu ý về việc sử dụng chỉ mục một phần.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Đây là Postgres 9.3, nhưng tôi tin rằng kết quả sẽ gần như tương tự vào ngày 9.1, mặc dù nó sẽ không sử dụng "Quét chỉ mục lục".

Chỉnh sửa: Tôi thấy bạn đã làm rõ câu hỏi ban đầu của mình và rõ ràng bạn đang tự hỏi tại sao Postgres không sử dụng chỉ mục trong một ví dụ đơn giản như:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Có lẽ bởi vì bạn không có bất kỳ hàng nào trong bảng. Vì vậy, thêm một số dữ liệu thử nghiệm và ANALYZE my_table;.


Trong phần mô tả cuốn sách đã nói (nhấn mạnh của tôi): "Tác giả Dan Tow phác thảo một phương pháp tiết kiệm thời gian mà ông đã phát triển để tìm ra kế hoạch thực hiện tối ưu - nhanh chóng và có hệ thống - bất kể sự phức tạp của SQL hay nền tảng cơ sở dữ liệu đang được sử dụng " Ngoài ra, có lẽ bạn đã bỏ qua # 1 của câu hỏi, cụ thể là, cột được định nghĩaNOT NULL, không phải là truy vấn sử dụng IS NOT NULLlàm điều kiện chỉ mục của nó. Đây là trong các ý kiến ​​bạn tham khảo, nhưng tôi sẽ cập nhật câu hỏi để đưa nó vào.
FuriousFolder

Hơn nữa, bản thân cuốn sách là bất khả tri về ngôn ngữ: các phần cụ thể duy nhất của DMBS là về hiển thị các kế hoạch truy vấn, mà Postgres thực hiện khá đơn giản :)
FuriousFolder

1
@FquilFolder cột được định nghĩa là KHÔNG NULL nhưng phần này (trong câu hỏi của bạn, từ cuốn sách): "Indexed_Col IS NOT NULL bao gồm ..." đề cập đến điều kiện vị trí và không phải là định nghĩa cột. Mặc dù thật khó để chắc chắn, vì nó nằm ngoài ngữ cảnh. Có lẽ bạn nên bao gồm toàn bộ đoạn (trước) từ cuốn sách.
ypercubeᵀᴹ

-1

Bạn chưa đăng truy vấn hoặc dữ liệu ví dụ của bạn. Nhưng các chỉ số lý do phổ biến nhất không được sử dụng phải liên quan đến khối lượng.

Các chỉ mục giống như một danh bạ dịch một cột thành một vị trí hàng. Nếu bạn chỉ tìm kiếm một vài hàng, sẽ rất hợp lý khi tìm kiếm từng hàng trong danh bạ, sau đó tìm kiếm hàng trong bảng chính.

Nhưng đối với nhiều hơn một vài hàng, việc bỏ qua danh bạ và lặp lại trên tất cả các hàng trong bảng chính sẽ rẻ hơn. Theo kinh nghiệm của tôi, điểm tới hạn là khoảng 100 hàng.


"Các chỉ mục giống như một danh bạ dịch một cột thành một vị trí hàng. Nếu bạn chỉ tìm kiếm một vài hàng, sẽ có ý nghĩa khi tra cứu từng hàng trong danh bạ, và sau đó tìm kiếm hàng trong bảng chính." Trên thực tế, các chỉ mục giống như các danh bạ nhỏ hơn được cập nhật bất cứ khi nào danh bạ mà chúng lập chỉ mục được cập nhật. Bạn biết rằng bất cứ khi nào bạn mở một danh bạ nhỏ hơn, bạn sẽ tìm thấy bất kỳ và tất cả thông tin mà điều kiện lập chỉ mục của nó mô tả. Ví dụ: Tất cả những người có tên 'thẳng thắn' trên bảng chỉ mục : CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder

Điều này cho phép một chỉ số chỉ quét được nhiều hơn nhanh hơn, vì bạn có thể đọc toàn bộ "danh bạ nhỏ" vào bộ nhớ, mà không phải là khả thi với nhiều triệu bảng lót.
FuriousFolder

@FurdyFolder: Bạn đang mô tả một lần quét chỉ mục. Nhưng OP nói rằng các chỉ mục của anh ta không được sử dụng, điều này sẽ không xảy ra nếu việc quét chỉ mục sẽ thỏa mãn truy vấn.
Andomar

Andomar ... Tôi OP, haha. Mục tiêu của tôi là chính xác đó; để có được truy vấn này để sử dụng quét chỉ mục. Tôi đã kể từ khi đạt được nó, vì Craig giải thích rằng postgres có thể sử dụng một chỉ mục trên một cột nơi định nghĩa của cột bao gồm NOT NULL
FuriousFolder
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.