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 LATERAL
và mmsi,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.