min () / max () trên chỉ mục dấu thời gian nhiều cột


7

Tôi cảm thấy khó hiểu tại sao có một loạt các đống tải đang diễn ra trong truy vấn này. Theo hiểu biết của tôi, khi không có null (ở hai đầu) trong chỉ mục, việc tìm kiếm ngược lại chỉ mục sẽ nhanh như tìm kiếm trực tiếp và ngược lại.

Tôi nghi ngờ rằng quét tiến / lùi thực sự là một cá trích đỏ, nhưng tôi không thể nhận ra bất kỳ sự khác biệt có ý nghĩa nào khác trong đầu ra giải thích này.

Đây là cách bố trí bảng. Tôi đã ẩn danh hai cột đầu tiên mà tôi tin rằng không liên quan đến vấn đề, nhưng tôi đã giữ chúng và các chỉ mục của chúng để hoàn thiện.

testqueuedb=> \d+ queue
                                                                  Table "public.queue"
        Column         |           Type           |                          Modifiers                          | Storage  | Stats target | Description
-----------------------+--------------------------+-------------------------------------------------------------+----------+--------------+-------------
 foo                   | character varying(64)    | not null                                                    | extended |              |
 bar                   | numeric(6,0)             | not null                                                    | main     |              |
 worker                | character varying(32)    | not null                                                    | extended |              |
 queued                | timestamp with time zone | not null default (timeofday())::timestamp without time zone | plain    |              |
Indexes:
    "queue_idx_job" btree (foo, bar, worker)
    "queue_idx_worker" btree (worker, queued)
Foreign-key constraints:
    "queue_fk_worker" FOREIGN KEY (worker) REFERENCES workers(worker)

Và đây là những giải thích tối thiểu / tối đa khác nhau.

testqueuedb=> explain (analyze, buffers) select min(queued) from queue where worker = 'workername';
                                                                        QUERY PLAN                              
----------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.59..0.60 rows=1 width=0) (actual time=1019.490..1019.490 rows=1 loops=1)
   Buffers: shared hit=20194 read=1
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.42..0.59 rows=1 width=8) (actual time=1019.485..1019.486 rows=1 loops=1)
           Buffers: shared hit=20194 read=1
           ->  Index Only Scan using queue_idx_worker on queue  (cost=0.42..55480.93 rows=330371 width=8) (actual time=1019.483..1019.483 rows=1 loops=1)
                 Index Cond: ((worker = 'workername'::text) AND (queued IS NOT NULL))
                 Heap Fetches: 20224
                 Buffers: shared hit=20194 read=1
 Planning time: 0.197 ms
 Execution time: 1019.529 ms
(11 rows)

testqueuedb=> explain (analyze, buffers) select max(queued) from queue where worker = 'workername';
                                                                         QUERY PLAN                             
-------------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.59..0.60 rows=1 width=0) (actual time=0.508..0.509 rows=1 loops=1)
   Buffers: shared hit=2 read=3
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.42..0.59 rows=1 width=8) (actual time=0.503..0.503 rows=1 loops=1)
           Buffers: shared hit=2 read=3
           ->  Index Only Scan Backward using queue_idx_worker on queue  (cost=0.42..55480.93 rows=330371 width=8) (actual time=0.502..0.502 rows=1 loops=1)
                 Index Cond: ((worker = 'workername'::text) AND (queued IS NOT NULL))
                 Heap Fetches: 1
                 Buffers: shared hit=2 read=3
 Planning time: 0.215 ms
 Execution time: 0.546 ms
(11 rows)

Tôi thấy các đống tải trong ví dụ đầu tiên này đặc biệt khó hiểu. Có phải tất cả đi xuống để đệm?

Phiên bản Postgres là 9.5.5.

Có khoảng 500.000 hàng cho mỗi công nhân trong bảng và rất ít công nhân riêng biệt - ít hơn mười - khiến tôi nghĩ rằng chỉ số không thực sự được cấu trúc chính xác để bắt đầu, nhưng tôi quan tâm đến sự khác biệt trong các truy vấn này bất kể.


1
select queued from queue where worker = 'workername' order by queued limit 1;hiển thị cùng một hành vi / giải thích?
ypercubeᵀᴹ

@ ypercubeᵀᴹ Vâng, đúng vậy. Tương tự, lật thứ tự desctrong truy vấn đó làm cho nó gần như ngay lập tức.
dùng115675

1
@ user115675 Tôi vừa thử tái tạo vấn đề của bạn trên postgres 9.5 - không thành công. Bảng xếp hàng của tôi có phân phối giống như bạn mô tả. Bảng khoảng 400 MB, chỉ số khoảng 150 MB. Các kế hoạch là như nhau, nhưng các bộ đệm nhỏ hơn nhiều và không có sự bất thường về heap. Vui lòng cung cấp thêm thông tin về tập dữ liệu (kích thước chính xác,
lần thứ mười,

Điều này có áp dụng không? dba.stackexchange.com/help/merging-accounts
Michael Green

2
Đó là một thực hành tốt để chạy mỗi giải thích hai lần để xem hiệu ứng của bộ nhớ đệm. Điều này làm cho một sự khác biệt?
Franc Drobnič

Câu trả lời:


1

Tôi khá chắc chắn điều này là do sự lựa chọn dấu thời gian làm kiểu dữ liệu cho queuedcột. Postgres phải truy cập tất cả các cột để đảm bảo rằng nó đã tìm thấy mức tối đa thực sự, vì các cân nhắc về múi giờ. Đây là lý do tại sao quét chỉ mục cho thấy số lượng cao như vậy.

Bạn nên thay đổi queuedkiểu dữ liệu thành một int (hoặc bigint) và tự động điều chỉnh nó với một chuỗi. (Tất nhiên bạn có thể để cột dấu thời gian trong nếu bạn cần giá trị).


Tôi không nghĩ vì vậy dấu thời gian chỉ là dấu thời gian trong vùng UTC, không cần chuyển đổi để so sánh chúng. (trên đĩa, đó là số lượng lớn micro giây)
Jasen
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.