2015-10-16 21 views
5

PostgreSQL 9.4 Bảng này được tạo ra như sau:Tại sao không thể chỉ sử dụng Chỉ mục Quét trên chỉ mục được tạo với COALESCE?

CREATE TABLE foo (
    id integer, 
    date date, 
    value numeric(14,3) 
); 

tôi tối ưu hóa một truy vấn bằng cách sử dụng chức năng ROW_NUMBER() cửa sổ và COALESCE. Cho hiệu quả nhất, tôi có xu hướng sử dụng Index Only Scan trong truy vấn sau đây:

SELECT id, c_val 
FROM (
    SELECT id, COALESCE(value, 0) c_val, ROW_NUMBER() OVER(PARTITION BY id ORDER BY date DESC NULLS LAST) rn 
    FROM foo) sbt 
WHERE sbt.rn = 1; 

Vì vậy, nếu tôi tạo ra các chỉ số như sau:

CREATE INDEX ON foo (id, date DESC NULLS LAST, value); 

các nhà quy hoạch chọn để sử dụng Index Only Scan, nhưng nếu tôi làm theo cách này:

CREATE INDEX ON foo (id, date DESC NULLS LAST, COALESCE(value, 0)); 

người lập kế hoạch sẽ làm chỉ Index Scan.

Tại sao? Tôi đang cố gắng tránh chi phí đánh giá chức năng COALESCE trong khi thực hiện truy vấn. Tại sao nó không hoạt động với Index Only Scan?

+2

"Chi phí" của 'coalesce()' gần bằng 0, đừng lo lắng về điều đó. –

Trả lời

1

Tôi nghĩ bạn đã giả định sai rằng COALESCE(value, 0) trong các sự cố SELECT của mình về việc sử dụng chỉ mục. Để nói sự thật nó chỉ xem chuyển đổi thực hiện sau khi các giá trị hàng được trả về.

Điều quan trọng liên quan đến việc sử dụng chỉ mục là WINDOW FUNCTION của bạn. Trước tiên, bạn phân vùng theo số id và seccondly bạn đặt giá trị trong mỗi phân vùng theo date DESC NULLS LAST. Hai điều này xác định rằng chỉ mục như CREATE INDEX ON foo (id, date DESC NULLS LAST, ...) hữu ích cho bất kỳ điều gì bạn đặt ở các vị trí tiếp theo. Lưu ý rằng nếu bạn thay đổi thứ tự iddate khi tạo chỉ mục, PostgreSQL sẽ không sử dụng chỉ mục nào cả.

Bây giờ, bạn phải biết rằng INDEX ONLY SCAN chỉ có thể được sử dụng nếu chính chỉ mục lưu trữ toàn bộ giá trị hàng bị ảnh hưởng do truy vấn yêu cầu. Sau PostgreSQL manual:

Nếu các cửa hàng chỉ mục các giá trị ban đầu được lập chỉ mục dữ liệu (và không phải một số đại diện tổn hao trong số họ), nó rất hữu ích để hỗ trợ quét chỉ số duy nhất, trong đó chỉ số trả về dữ liệu thực tế ...

trong trường hợp của bạn mình cũng bán những chỉ số seccond một số đại diện lossy của một hàng bởi vì giá trị của cột cuối cùng được biến đổi bởi một chức năng và truy vấn yêu cầu id, valuedate. PostgreSQL không quá thông minh để thấy rằng nó chỉ thay thế NULLs bởi 0. Đối với anh ta, nó không phải là giá trị ban đầu. Vì vậy, chúng ta cần phải truy cập vào bảng để có được các giá trị hàng ban đầu (cuối cùng bằng cách sử dụng đồng bằng). Sau đó các giá trị được định dạng cho đầu ra và COALESCE(values, 0) xảy ra.

Edit:

Tôi nghĩ rằng lời giải thích đó là đủ để bạn như xa như câu hỏi của bạn về internals là có liên quan. Để nói về COALECE() chi phí đánh giá, tôi đồng ý với a_horse_with_no_name rằng bạn có thể không nên lo lắng về điều đó.

+0

Ah, tôi không biết rằng việc tìm nạp xảy ra trước tiên trong trường hợp 'COALESCE', nếu tôi có thể nói như vậy ... –

+0

Vì tôi đã trả lời bạn câu hỏi một cách chính xác và giải thích mọi thứ. bạn nói nó) tại sao không chấp nhận câu trả lời của tôi? –

+0

Chỉ cần quên làm điều này ... –

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