con grandes conjuntos de datos, window functions son la forma más eficiente para llevar a cabo este tipo de consultas - la tabla se escanea una sola vez, en lugar de una vez para cada fecha, como lo haría una auto unión. También parece mucho más simple. :) PostgreSQL 8.4 y posteriores tienen soporte para funciones de ventana.
Esto es lo que parece:
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM subscriptions
GROUP BY created_at;
Aquí OVER
crea la ventana; ORDER BY created_at
significa que tiene que resumir los recuentos en el orden created_at
.
Editar: Si desea eliminar correos electrónicos duplicados dentro de un solo día, se puede utilizar sum(count(distinct email))
. Lamentablemente, esto no eliminará los duplicados que cruzan diferentes fechas.
Si desea eliminar todos los duplicados, creo que lo más sencillo es utilizar una subconsulta y DISTINCT ON
. Esto atribuir correos electrónicos a su fecha más temprana (porque estoy clasificación por created_at en orden ascendente, que va a elegir la más temprana):
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;
Si crea un índice en (email, created_at)
, esta consulta no debe ser demasiado lento tampoco.
(Si desea probar, así es como he creado el conjunto de datos de muestra)
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);
Esto es genial intgr, solo que mi la tabla de suscripciones contiene muchas filas de correo electrónico duplicadas. Entonces, lo que 'sobre' está haciendo es 'sumar' los números de 'conteo', pero aún tengo que volver a calcular los correos electrónicos únicos en cada fecha posterior. – Khairul
Actualicé mi respuesta con una subconsulta 'DISTINCT ON'. Todavía es mucho más rápido que la respuesta de Andriy: puede procesar un millón de filas en pocos segundos, pero quizás sea más complicado. – intgr
¡Buen consejo sobre la función generate_series! –