Với bộ dữ liệu lớn hơn, chức năng cửa sổ là cách hiệu quả nhất để thực hiện các loại truy vấn này - bảng sẽ chỉ được quét một lần, thay vì một lần cho mỗi ngày, như tự tham gia sẽ làm. Nó cũng trông đơn giản hơn rất nhiều. :) PostgreSQL 8.4 trở lên có hỗ trợ các chức năng cửa sổ.
Nó trông như thế này:
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM subscriptions
GROUP BY created_at;
Đây OVER
tạo cửa sổ; ORDER BY created_at
có nghĩa là nó phải tính tổng số trong created_at
đặt hàng.
Chỉnh sửa: Nếu bạn muốn xóa các email trùng lặp trong vòng một ngày, bạn có thể sử dụng sum(count(distinct email))
. Rất tiếc, điều này sẽ không xóa các bản sao qua các ngày khác nhau.
Nếu bạn muốn xóa tất cả trùng lặp, tôi nghĩ đơn giản nhất là sử dụng truy vấn con và DISTINCT ON
. Điều này sẽ quy các email đến ngày sớm nhất của chúng (vì tôi đang sắp xếp theo create_at theo thứ tự tăng dần, nó sẽ chọn ngày sớm nhất):
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM (
SELECT DISTINCT ON (email) created_at, email
FROM subscriptions ORDER BY email, created_at
) AS subq
GROUP BY created_at;
Nếu bạn tạo chỉ mục trên (email, created_at)
, truy vấn này cũng không được quá chậm.
(Nếu bạn muốn kiểm tra, đây là cách tôi tạo tập dữ liệu mẫu)
create table subscriptions as
select date '2000-04-04' + (i/10000)::int as created_at,
'[email protected]' || (i%700000)::text as email
from generate_series(1,1000000) i;
create index on subscriptions (email, created_at);