En mi experiencia (y como se muestra en muchas pruebas) NOT IN
como lo demostró @gsiems es bastante lento y se escala terriblemente. El inverso IN
suele ser más rápido (donde puede reformular de esa manera, como en este caso), pero esta consulta con EXISTS
(hacer exactamente lo que pidió) debería ser mucho más rápida todavía, con tablas grandes por orden de magnitud :
DELETE FROM questions_tags q
WHERE EXISTS (
SELECT FROM questions_tags q1
WHERE q1.ctid < q.ctid
AND q1.question_id = q.question_id
AND q1.tag_id = q.tag_id
);
Elimina cada fila donde existe otra fila con la misma (tag_id, question_id)
y una más pequeñactid
. (Efectivamente mantiene la primera instancia de acuerdo con el orden físico de las tuplas). Utilizando ctid
en ausencia de una mejor alternativa, su tabla no parece tener una PK o cualquier otra (s) columna (s) única (s).
ctid
es el identificador interno de tupla presente en cada fila y necesariamente único. Otras lecturas:
Prueba
Ejecuté un caso de prueba con esta tabla adaptada a su pregunta y 100k filas:
CREATE TABLE questions_tags(
question_id integer NOT NULL
, tag_id integer NOT NULL
);
INSERT INTO questions_tags (question_id, tag_id)
SELECT (random()* 100)::int, (random()* 100)::int
FROM generate_series(1, 100000);
ANALYZE questions_tags;
Los índices no ayudan en este caso.
Resultados
NOT IN
El SQLfiddle agota el tiempo de espera.
Intenté lo mismo localmente pero también lo cancelé, después de varios minutos.
EXISTS
Termina en medio segundo en este SQLfiddle .
Alternativas
Si va a eliminar la mayoría de las filas , será más rápido seleccionar a los sobrevivientes en otra tabla, soltar el original y cambiar el nombre de la tabla del sobreviviente. Cuidado, esto tiene implicaciones si tiene claves externas o de vista (u otras dependencias) definidas en el original.
Si tiene dependencias y desea conservarlas, podría:
- Descarte todas las claves e índices foráneos para obtener rendimiento.
SELECT
sobrevivientes a una mesa temporal.
TRUNCATE
el original.
- Revivientes
INSERT
.
- Re-
CREATE
índices y claves foráneas. Las vistas solo pueden permanecer, no tienen impacto en el rendimiento. Más aquí o aquí .