Nella mia esperienza (e come mostrato in molti test) NOT IN
come 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 ctid
in 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-
INSERT
sopravvissuti.
- Reindicizza
CREATE
e chiavi esterne. Le viste possono semplicemente rimanere, non hanno alcun impatto sulle prestazioni. Più qui o qui .