Làm thế nào để sử dụng chỉ mục để tăng tốc độ sắp xếp trong postgres


10

Tôi đang sử dụng postgres 9.4.

messageslược đồ sau: tin nhắn thuộc về feed_id và đã đăng_at, cũng có thể có tin nhắn gốc (trong trường hợp trả lời).

                    Table "public.messages"
            Column            |            Type             | Modifiers
------------------------------+-----------------------------+-----------
 message_id                   | character varying(255)      | not null
 feed_id                      | integer                     |
 parent_id                    | character varying(255)      |
 posted_at                    | timestamp without time zone |
 share_count                  | integer                     |
Indexes:
    "messages_pkey" PRIMARY KEY, btree (message_id)
    "index_messages_on_feed_id_posted_at" btree (feed_id, posted_at DESC NULLS LAST)

Tôi muốn trả về tất cả các tin nhắn theo thứ tự share_count, nhưng với mỗi parent_idtin nhắn, tôi chỉ muốn trả lại một tin nhắn. tức là, nếu nhiều tin nhắn có cùng parent_id, thì chỉ có tin nhắn mới nhất ( posted_at) được trả về. Có parent_idthể là null, tin nhắn có null parent_idnên trả về tất cả.

Truy vấn tôi đã sử dụng là:

WITH filtered_messages AS (SELECT * 
                           FROM messages
                           WHERE feed_id IN (7) 
                           AND (posted_at >= '2015-01-01 04:00:00.000000') 
                           AND (posted_at < '2015-04-28 04:00:00.000000'))
    SELECT *
    FROM (SELECT DISTINCT ON(COALESCE(parent_id, message_id)) parent_id,
                          message_id, 
                          posted_at, 
                          share_count
          FROM filtered_messages
          ORDER BY COALESCE(parent_id, message_id), posted_at DESC NULLS LAST
         ) messages
    ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;

Đây là http://sqlfiddle.com/#!15/588e5/1/0 , trong SQL Fiddle, tôi đã xác định lược đồ, truy vấn chính xác và kết quả mong đợi.

Nhưng hiệu năng của truy vấn chậm khi bảng thông báo trở nên lớn. Tôi đã thử thêm nhiều chỉ mục sắp xếp, nhưng dường như không sử dụng chỉ mục. Đây là lời giải thích: http://explain.depesz.com/s/Sv2

Làm thế nào tôi có thể tạo một chỉ mục chính xác?


Trong cái nhìn đầu tiên, ORDER BYtrong truy vấn con là hoàn toàn vô dụng. Hơn nữa, kế hoạch được liên kết không thể là kết quả của truy vấn được đăng - chẳng hạn, không có đề cập đến metadata.
dezso

Mô tả của bạn không đề cập đến vai trò của feed_idposted_atvà bạn hoàn toàn không đề cập đến metadata, đây có vẻ là một loại JSON? Vui lòng sửa chữa câu hỏi của bạn để làm cho nó phù hợp. Bạn chọn> 500k hàng trong CTE ... Có bao nhiêu hàng trong bảng? Bao nhiêu phần trăm hàng bạn thường chọn trong CTE? Bao nhiêu phần trăm hàng có parent_id IS NULL? Xem xét thông tin trong thẻ [postgresql-Performance] cho các câu hỏi về hiệu suất.
Erwin Brandstetter

Cũng quan trọng: Có bao nhiêu hàng cho mỗi parent_id? (tối thiểu / avg / max)
Erwin Brandstetter

xin lỗi, tôi đã cố gắng làm cho câu hỏi rõ ràng hơn bằng cách giảm một số cột, share_count thực sự nằm trong hstore metadata. Hiện tại bảng tin nhắn có 10 triệu dữ liệu, nhưng tăng nhanh. Tôi nghĩ sẽ tách thành các bảng phân vùng cho mỗi feed_id. Vì tôi chỉ tìm nạp trên mỗi id nguồn cấp dữ liệu. tỷ lệ phần trăm của cha_id null so với không null là khoảng 60% / 40%. một lần tìm nạp thông thường là khoảng 1-2% của bảng. (khoảng 100 nghìn tin nhắn) Hiệu suất cho 100K là khoảng 1 giây, nhưng một khi đạt tới 500K +, nó sử dụng chỉ số bitmap và thường mất 10 giây.
Zhaohan Weng

Câu trả lời:


9

Truy vấn

Truy vấn này sẽ nhanh hơn đáng kể trong mọi trường hợp:

SELECT parent_id, message_id, posted_at, share_count
FROM   messages
WHERE  feed_id = 7
AND    posted_at >= '2015-01-01 4:0:0'
AND    posted_at <  '2015-04-28 4:0:0'
AND    parent_id IS NULL  -- match index condition
UNION ALL
(
SELECT DISTINCT ON(parent_id)
       parent_id, message_id, posted_at, share_count
FROM   messages
WHERE  feed_id = 7
AND    posted_at >= '2015-01-01 4:0:0'
AND    posted_at <  '2015-04-28 4:0:0'
AND    parent_id IS NOT NULL  -- match index condition
ORDER  BY parent_id, posted_at DESC NULLS LAST
)
ORDER  BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
  • CTE không làm gì ở đây mà một truy vấn con đơn giản cũng không thể cung cấp. Và CTE giới thiệu một rào cản tối ưu hóa vì nó được thực hiện riêng biệt và kết quả của nó được cụ thể hóa.

  • Bạn có thêm một cấp độ truy vấn con hơn mức bạn thực sự cần.

  • Biểu thức (COALESCE(parent_id, message_id)không tương thích với một chỉ mục đơn giản, bạn sẽ cần một chỉ mục trên biểu thức đó. Nhưng điều đó có thể cũng không hữu ích lắm, tùy thuộc vào phân phối dữ liệu. Theo liên kết của tôi dưới đây để biết thông tin chi tiết.

  • Việc tách trường hợp đơn giản parent_id IS NULLthành riêng biệt SELECTcó thể hoặc không thể cung cấp tối ưu. Đặc biệt là không, nếu đó là trường hợp hiếm gặp, trong trường hợp đó, một truy vấn kết hợp với chỉ mục trên (COALESCE(parent_id, message_id)có thể hoạt động tốt hơn. Những cân nhắc khác áp dụng ...

Chỉ số

Đặc biệt là khi được hỗ trợ với các chỉ số này:

CREATE INDEX messages_idx_null ON messages (
  feed_id
, posted_at DESC NULLS LAST
, share_count DESC NULLS LAST
, parent_id, message_id
)
WHERE parent_id IS NULL;

CREATE INDEX messages_idx_notnull ON messages (
  feed_id
, posted_at DESC NULLS LAST
, share_count DESC NULLS LAST
, parent_id, message_id
)
WHERE parent_id IS NOT NULL;

Hai chỉ số một phần bao gồm toàn bộ bảng với nhau và có cùng kích thước với nhau như một chỉ số tổng.

Hai cột cuối cùng parent_id, message_idchỉ có ý nghĩa nếu bạn quét chỉ mục từ nó. Khác loại bỏ chúng từ cả hai chỉ số.

Câu đố SQL.

Tùy thuộc vào chi tiết bị thiếu, DISTINCT ONcó thể hoặc không thể là kỹ thuật truy vấn tốt nhất cho mục đích. Đọc giải thích chi tiết tại đây:

Và có thể thay thế nhanh hơn ở đây:

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.