Dalam pengalaman saya (dan seperti yang ditunjukkan dalam banyak tes) NOT IN
seperti yang ditunjukkan oleh @ gsiems agak lambat dan skala sangat. Kebalikannya IN
biasanya 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 ctid
ada . (Secara efektif menyimpan instance pertama sesuai dengan urutan fisik tupel.) Dengan ctid
tidak adanya alternatif yang lebih baik, meja Anda tampaknya tidak memiliki PK atau kolom (set) unik lainnya.
ctid
adalah 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-
INSERT
selamat.
- Mengindeks ulang
CREATE
dan kunci asing. Tampilan bisa tetap, mereka tidak berdampak pada kinerja. Lebih banyak di sini atau di sini .
Anda dapat menggunakan ctid untuk mencapai itu. Sebagai contoh:
Buat tabel dengan duplikat:
Pilih data duplikat:
Hapus data duplikat:
Dalam kasus Anda, yang berikut ini harus berfungsi:
sumber
ctid
? Terima kasih.ctid
?