PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Cách thích hợp để truy cập hàng mới nhất cho từng số nhận dạng riêng lẻ?

Dưới đây là so sánh hiệu suất nhanh cho các truy vấn được đề cập trong bài đăng này.

Thiết lập hiện tại:

Bảng core_message có 10.904.283 hàng và có 60.740 hàng trong test_boats (hoặc 60.740 mmsi riêng biệt trong core_message ).

Và tôi đang sử dụng PostgreSQL 11.5

Truy vấn bằng cách sử dụng quét chỉ lập chỉ mục:

1) sử dụng DISTINCT ON :

SELECT DISTINCT ON (mmsi) mmsi 
FROM core_message;

2) sử dụng RECURSIVE với LATERAL :

WITH RECURSIVE cte AS (
   (
   SELECT mmsi
   FROM   core_message
   ORDER  BY mmsi
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT mmsi
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi
      LIMIT  1
      ) m
   )
TABLE cte;

3) Sử dụng một bảng bổ sung với LATERAL :

SELECT a.mmsi
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.time
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

Truy vấn không sử dụng tính năng quét chỉ lập chỉ mục:

4) sử dụng DISTINCT ON với mmsi,time DESC INDEX :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi, time desc;

5) sử dụng DISTINCT ON với mmsi,time lùi lại UNIQUE CONSTRAINT :

SELECT DISTINCT ON (mmsi) * 
FROM core_message 
ORDER BY mmsi desc, time desc;

6) sử dụng RECURSIVE với LATERALmmsi,time DESC INDEX :

WITH RECURSIVE cte AS (
   (
   SELECT *
   FROM   core_message
   ORDER  BY mmsi , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi > c.mmsi
      ORDER  BY mmsi , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

7) sử dụng RECURSIVE với LATERAL và lùi lại mmsi,time UNIQUE CONSTRAINT :

WITH RECURSIVE cte AS (

   (

   SELECT *
   FROM   core_message
   ORDER  BY mmsi DESC , time DESC 
   LIMIT  1
   )
   UNION ALL
   SELECT m.*
   FROM   cte c
   CROSS  JOIN LATERAL (
      SELECT *
      FROM   core_message
      WHERE  mmsi < c.mmsi
      ORDER  BY mmsi DESC , time DESC 
      LIMIT  1
      ) m
   )
TABLE cte;

8) Sử dụng một bảng bổ sung với LATERAL :

SELECT b.*
FROM test_boats a
CROSS JOIN LATERAL(
    SELECT b.*
    FROM core_message b
    WHERE a.mmsi = b.mmsi
    ORDER BY b.time DESC
    LIMIT 1
) b;

Sử dụng một bảng dành riêng cho tin nhắn cuối cùng:

9) Đây là giải pháp ban đầu của tôi, sử dụng một bảng riêng biệt chỉ có thông báo cuối cùng. Bảng này được điền khi có thư mới nhưng cũng có thể được tạo như vậy:

CREATE TABLE core_shipinfos AS (
    WITH RECURSIVE cte AS (
       (
       SELECT *
       FROM   core_message
       ORDER  BY mmsi DESC , time DESC 
       LIMIT  1
       )
       UNION ALL
       SELECT m.*
       FROM   cte c
       CROSS  JOIN LATERAL (
          SELECT *
          FROM   core_message
          WHERE  mmsi < c.mmsi
          ORDER  BY mmsi DESC , time DESC 
          LIMIT  1
          ) m
       )
    TABLE cte);

Sau đó, yêu cầu nhận thông báo mới nhất rất đơn giản như sau:

SELECT * FROM core_shipinfos;

Kết quả:

Trung bình của nhiều truy vấn (khoảng 5 đối với truy vấn nhanh):

1) 9146 mili giây
2) 728 mili giây
3) 498 mili giây

4) 51488 mili giây
5) 54764 mili giây
6) 729 mili giây
7) 778 mili giây
8) 516 mili giây

9) 15 mili giây

Kết luận:

Tôi sẽ không bình luận về giải pháp bảng chuyên dụng và sẽ giữ điều đó cho đến cuối.

Bảng bổ sung (test_boats ) giải pháp chắc chắn là người chiến thắng ở đây nhưng RECURSIVE giải pháp cũng khá hiệu quả.

Có một khoảng cách lớn về hiệu suất cho DISTINCT ON bằng cách sử dụng quét chỉ chỉ mục và không sử dụng nó, nhưng hiệu suất đạt được là khá nhỏ đối với truy vấn hiệu quả khác.

Điều này có ý nghĩa vì cải tiến lớn mà các truy vấn đó mang lại là thực tế là chúng không cần lặp lại toàn bộ core_message nhưng chỉ trên một tập hợp con của mmsi duy nhất nhỏ hơn đáng kể (60K +) so với core_message kích thước bảng (10M +)

Một lưu ý bổ sung, dường như không có sự cải thiện đáng kể về hiệu suất đối với các truy vấn sử dụng UNIQUE CONSTRAINT nếu tôi đánh rơi mmsi,time DESC INDEX . Nhưng giảm chỉ mục đó tất nhiên sẽ tiết kiệm cho tôi một số dung lượng (chỉ mục này hiện chiếm 328MB)

Giới thiệu về giải pháp bảng chuyên dụng:

Mỗi thư được lưu trữ trong core_message bảng chứa cả thông tin vị trí (vị trí, tốc độ, hướng đi, v.v.) VÀ thông tin về tàu (tên, ký hiệu, kích thước, v.v.), cũng như số nhận dạng tàu (mmsi).

Để cung cấp thêm một chút thông tin cơ bản về những gì tôi đang thực sự cố gắng thực hiện:Tôi đang triển khai một chương trình phụ trợ để lưu trữ các thông báo do tàu gửi qua Giao thức AIS .

Như vậy, mọi mmsi duy nhất mà tôi nhận được, tôi nhận được nó thông qua giao thức này. Nó không phải là một danh sách được xác định trước. Nó tiếp tục thêm MMSI mới cho đến khi tôi nhận được mọi tàu trên thế giới sử dụng AIS.

Trong bối cảnh đó, một bảng dành riêng với thông tin về tàu như tin nhắn cuối cùng nhận được có ý nghĩa.

Tôi có thể tránh sử dụng bảng như chúng ta đã thấy với RECURSIVE giải pháp, nhưng ... một bảng chuyên dụng vẫn nhanh hơn 50 lần so với RECURSIVE này giải pháp.

Trên thực tế, bảng chuyên dụng đó tương tự như test_boat bảng, với nhiều thông tin hơn chỉ là mmsi đồng ruộng. Như hiện tại, có một bảng với mmsi chỉ trường hoặc một bảng với mọi thông tin cuối cùng của core_message bảng thêm độ phức tạp tương tự vào ứng dụng của tôi.

Cuối cùng, tôi nghĩ rằng tôi sẽ đi cho chiếc bàn chuyên dụng này. Nó sẽ mang lại cho tôi tốc độ vô địch và tôi vẫn có thể sử dụng LATERAL lừa trên core_message , điều này sẽ mang lại cho tôi sự linh hoạt hơn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL:Tìm chuỗi chung dài nhất giữa các hàng

  2. Chuyển đổi ngày Julian thành ngày lịch trong Postgresql

  3. Tạo chỉ mục đa cột để thực thi tính duy nhất

  4. Cách truy vấn một phần tử JSON

  5. PGError:ERROR:quan hệ delay_jobs không tồn tại (Postgresql, rails 3.04, delay_job error)