300k hàng không phải là một bảng lớn. Chúng tôi thường xuyên nhìn thấy 300 triệu bảng hàng.
Vấn đề lớn nhất với truy vấn của bạn là bạn đang sử dụng một truy vấn con có tương quan, vì vậy nó phải thực thi lại truy vấn con cho mỗi hàng trong truy vấn bên ngoài.
Thường thì bạn không cần phải làm tất cả công việc của bạn trong một câu lệnh SQL. Có những lợi thế khi chia nó thành một số câu lệnh SQL đơn giản hơn:
- Mã dễ dàng hơn.
- Dễ dàng tối ưu hóa hơn.
- Dễ dàng gỡ lỗi hơn.
- Dễ đọc hơn.
- Dễ dàng duy trì hơn nếu / khi bạn phải thực hiện các yêu cầu mới.
Số lượng mua hàng
SELECT customer, COUNT(sale) AS number_of_purchases
FROM sales
GROUP BY customer;
Chỉ mục về doanh số bán hàng (khách hàng, doanh số bán hàng) sẽ là tốt nhất cho truy vấn này.
Giá trị lần mua cuối cùng
Đây là lớn nhất-n-mỗi-nhóm vấn đề thường xuyên xảy ra.
SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
ON a.customer=b.customer AND a.dates < b.dates
WHERE b.customer IS NULL;
Nói cách khác, hãy thử đối sánh hàng a
đến một hàng giả định b
có cùng một khách hàng và một ngày lớn hơn. Nếu không tìm thấy hàng nào như vậy, thì a
phải có ngày quan trọng nhất cho khách hàng đó.
Chỉ mục về doanh số bán hàng (khách hàng, ngày tháng, doanh số bán hàng) sẽ là tốt nhất cho truy vấn này.
Nếu bạn có thể có nhiều hơn một lần bán hàng cho một khách hàng vào ngày quan trọng nhất đó, thì truy vấn này sẽ trả về nhiều hơn một hàng cho mỗi khách hàng. Bạn cần phải tìm một cột khác để phá vỡ sự ràng buộc. Nếu bạn sử dụng khóa chính tăng tự động, khóa này phù hợp làm bộ ngắt cà vạt vì nó được đảm bảo là duy nhất và có xu hướng tăng theo thứ tự thời gian.
SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL;
Tổng số tiền mua hàng, khi nó có giá trị dương
SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE sale > 0
GROUP BY customer;
Chỉ mục về doanh số bán hàng (khách hàng, doanh số bán hàng) sẽ là tốt nhất cho truy vấn này.
Bạn nên cân nhắc sử dụng NULL để biểu thị giá trị bán bị thiếu thay vì -1. Các hàm tổng hợp như SUM () và COUNT () bỏ qua NULL, vì vậy bạn không cần phải sử dụng mệnh đề WHERE để loại trừ các hàng có bán <0.
Re:nhận xét của bạn
Năm khách hàng hàng đầu cho Q4 2012
SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE (year, quarter) = (2012, 4) AND sale > 0
GROUP BY customer
ORDER BY total_purchases DESC
LIMIT 5;
Tôi muốn kiểm tra nó dựa trên dữ liệu thực, nhưng tôi tin rằng một chỉ số về doanh số bán hàng (năm, quý, khách hàng, bán hàng) sẽ là tốt nhất cho truy vấn này.
Lần mua cuối cùng cho những khách hàng có Tổng số lần mua> 5
SELECT a.customer, a.sale as max_sale
FROM sales a
INNER JOIN sales c ON a.customer=c.customer
LEFT OUTER JOIN sales b
ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL
GROUP BY a.id
HAVING COUNT(*) > 5;
Như trong truy vấn lớn nhất-n-mỗi nhóm khác ở trên, chỉ mục về doanh số bán hàng (khách hàng, ngày tháng, doanh số bán hàng) sẽ là tốt nhất cho truy vấn này. Nó có thể không thể tối ưu hóa cả tham gia và nhóm theo, vì vậy điều này sẽ phát sinh một bảng tạm thời. Nhưng ít nhất nó sẽ chỉ thực hiện một bảng tạm thời thay vì nhiều bảng.
Những truy vấn này đủ phức tạp. Bạn không nên cố gắng viết một truy vấn SQL duy nhất có thể cho tất cả trong số các kết quả này. Hãy nhớ câu nói kinh điển của Brian Kernighan: