Bij grotere datasets, vensterfuncties zijn de meest efficiënte manier om dit soort zoekopdrachten uit te voeren -- de tabel wordt slechts één keer gescand, in plaats van één keer voor elke datum, zoals een self-join zou doen. Het ziet er ook een stuk eenvoudiger uit. :) PostgreSQL 8.4 en hoger hebben ondersteuning voor vensterfuncties.
Zo ziet het eruit:
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM subscriptions
GROUP BY created_at;
Hier OVER
maakt het venster; ORDER BY created_at
betekent dat het de tellingen moet optellen in created_at
bestellen.
Bewerken: Als u dubbele e-mails binnen één dag wilt verwijderen, kunt u sum(count(distinct email))
gebruiken . Helaas worden hiermee geen duplicaten verwijderd die verschillende datums overschrijden.
Als u alle wilt verwijderen duplicaten, ik denk dat het het gemakkelijkst is om een subquery te gebruiken en DISTINCT ON
. Hierdoor worden e-mails toegeschreven aan hun vroegste datum (omdat ik sorteer op create_at in oplopende volgorde, wordt de vroegste gekozen):
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;
Als u een index maakt op (email, created_at)
, moet deze zoekopdracht ook niet te langzaam zijn.
(Als je wilt testen, zo heb ik de voorbeelddataset gemaakt)
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);