Nella mia esperienza (e come mostrato in molti test) NOT INcome dimostrato da @gsiems è piuttosto lento e si ridimensiona terribilmente. L'inverso INè in genere più veloce (dove puoi riformulare in quel modo, come in questo caso), ma questa query con EXISTS(facendo esattamente quello che hai chiesto) dovrebbe essere ancora molto più veloce - con grandi tabelle per ordini di grandezza :
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 ogni riga in cui esiste un'altra riga con la stessa (tag_id, question_id)e una più piccolactid . (Mantiene efficacemente la prima istanza in base all'ordine fisico delle tuple.) Usando ctidin assenza di un'alternativa migliore, la tua tabella non sembra avere un PK o qualsiasi altra colonna (e) unica (serie).
ctidè l'identificatore di tupla interno presente in ogni riga e necessariamente unico. Ulteriori letture:
Test
Ho eseguito un caso di test con questa tabella corrispondente alla tua domanda e 100.000 righe:
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;
Gli indici non aiutano in questo caso.
risultati
NOT IN
Il timeout di SQLfiddle .
Ho provato lo stesso localmente ma l'ho annullato anche io, dopo alcuni minuti.
EXISTS
Termina in mezzo secondo in questo SQLfiddle .
alternative
Se hai intenzione di eliminare la maggior parte delle righe , sarà più veloce selezionare i sopravvissuti in un'altra tabella, eliminare l'originale e rinominare la tabella dei sopravvissuti. Attenzione, questo ha implicazioni se si hanno chiavi di visualizzazione o esterne (o altre dipendenze) definite sull'originale.
Se si dispone di dipendenze e si desidera mantenerle, è possibile:
- Rilascia tutte le chiavi esterne e gli indici - per prestazioni.
SELECT sopravvissuti a un tavolo temporaneo.
TRUNCATE l'originale.
- Ri-
INSERTsopravvissuti.
- Reindicizza
CREATEe chiavi esterne. Le viste possono semplicemente rimanere, non hanno alcun impatto sulle prestazioni. Più qui o qui .