Dalam pengalaman saya (dan seperti yang ditunjukkan dalam banyak tes) NOT INseperti yang ditunjukkan oleh @ gsiems agak lambat dan skala sangat. Kebalikannya INbiasanya lebih cepat (di mana Anda dapat memformulasikan ulang seperti itu, seperti dalam kasus ini), tetapi kueri dengan EXISTS(melakukan persis seperti yang Anda tanyakan) harus lebih cepat lagi - dengan tabel besar berdasarkan pesanan besarnya :
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
);
Menghapus setiap baris di mana baris lain dengan yang sama (tag_id, question_id)dan lebih kecil ctidada . (Secara efektif menyimpan instance pertama sesuai dengan urutan fisik tupel.) Dengan ctidtidak adanya alternatif yang lebih baik, meja Anda tampaknya tidak memiliki PK atau kolom (set) unik lainnya.
ctidadalah pengenal tuple internal yang hadir di setiap baris dan tentu saja unik. Bacaan lebih lanjut:
Uji
Saya menjalankan test case dengan tabel ini yang cocok dengan pertanyaan Anda dan 100 ribu baris:
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;
Indeks tidak membantu dalam kasus ini.
Hasil
NOT IN
Waktu SQLfiddle habis.
Mencoba yang sama secara lokal tetapi saya membatalkannya juga, setelah beberapa menit.
EXISTS
Selesai dalam setengah detik dalam SQLfiddle ini .
Alternatif
Jika Anda akan menghapus sebagian besar baris , akan lebih cepat untuk memilih yang selamat ke tabel lain, jatuhkan yang asli dan ganti nama tabel yang selamat. Hati-hati, ini berimplikasi jika Anda memiliki pandangan atau kunci asing (atau dependensi lainnya) yang ditentukan pada aslinya.
Jika Anda memiliki dependensi dan ingin mempertahankannya, Anda dapat:
- Jatuhkan semua kunci dan indeks asing - untuk kinerja.
SELECT selamat ke meja sementara.
TRUNCATE asli.
- Re-
INSERTselamat.
- Mengindeks ulang
CREATEdan kunci asing. Tampilan bisa tetap, mereka tidak berdampak pada kinerja. Lebih banyak di sini atau di sini .