Luôn có 2 điều cần xem xét khi tối ưu hóa các truy vấn:
- Những chỉ mục nào có thể được sử dụng (bạn có thể cần tạo chỉ mục)
- Cách truy vấn được viết (bạn có thể cần thay đổi truy vấn để cho phép người chọn truy vấn có thể tìm thấy các chỉ mục thích hợp và không đọc lại dữ liệu một cách dư thừa)
Một vài nhận xét:
-
Bạn đang thực hiện thao tác ngày tháng trước khi bạn tham gia các cuộc hẹn hò của mình. Theo nguyên tắc chung, điều này sẽ ngăn người chọn truy vấn sử dụng chỉ mục ngay cả khi nó tồn tại. Bạn nên cố gắng viết biểu thức của mình theo cách mà các cột được lập chỉ mục tồn tại không thay đổi ở một bên của biểu thức.
-
Các truy vấn con của bạn đang lọc theo cùng một phạm vi ngày với
generate_series
. Đây là một sự trùng lặp và nó hạn chế khả năng của nạn nhân trong việc chọn cách tối ưu hóa hiệu quả nhất. Tôi nghi ngờ rằng điều đó có thể đã được viết vào để cải thiện hiệu suất vì optimser không thể sử dụng chỉ mục trên cột ngày (body_time
)? -
LƯU Ý :Chúng tôi thực sự rất muốn sử dụng một chỉ mục trên
Body.body_time
-
ORDER BY
trong các truy vấn con là tốt nhất là dư thừa. Tệ nhất là nó có thể buộc trình tối ưu hóa truy vấn sắp xếp tập hợp kết quả trước khi tham gia; và điều đó không nhất thiết là tốt cho kế hoạch truy vấn. Thay vì chỉ áp dụng đặt hàng ngay ở phần cuối để hiển thị cuối cùng. -
Sử dụng
LEFT JOIN
trong truy vấn phụ của bạn là không phù hợp. Giả sử bạn đang sử dụng quy ước ANSI choNULL
hành vi (và bạn nên như vậy), bất kỳ bên ngoài tham gia vàoenvelope
sẽ trả vềenvelope_command=NULL
và do đó, những điều này sẽ bị loại trừ bởi điều kiệnenvelope_command=?
. -
Truy vấn con
o
vài
gần như giống hệt nhau được lưu choenvelope_command
giá trị. Điều này buộc người sử dụng phải quét các bảng bên dưới giống nhau hai lần. Bạn có thể sử dụng bảng tổng hợp kỹ thuật nối với dữ liệu một lần và chia các giá trị thành 2 cột.
Hãy thử cách sau sử dụng kỹ thuật xoay:
SELECT p.period,
/*The pivot technique in action...*/
SUM(
CASE WHEN envelope_command = 1 THEN body_size
ELSE 0
END) AS Outbound,
SUM(
CASE WHEN envelope_command = 2 THEN body_size
ELSE 0
END) AS Inbound
FROM (
SELECT date '2009-10-01' + s.day AS period
FROM generate_series(0, date '2009-10-31' - date '2009-10-01') AS s(day)
) AS p
/*The left JOIN is justified to ensure ALL generated dates are returned
Also: it joins to a subquery, else the JOIN to envelope _could_ exclude some generated dates*/
LEFT OUTER JOIN (
SELECT b.body_size,
b.body_time,
e.envelope_command
FROM body AS b
INNER JOIN envelope e
ON e.message_id = b.message_id
WHERE envelope_command IN (1, 2)
) d
/*The expressions below allow the optimser to use an index on body_time if
the statistics indicate it would be beneficial*/
ON d.body_time >= p.period
AND d.body_time < p.period + INTERVAL '1 DAY'
GROUP BY p.Period
ORDER BY p.Period
CHỈNH SỬA :Đã thêm bộ lọc do Tom H.
đề xuất