Saya mulai dengan googling, dan menemukan artikel ini yang membahas tentang tabel mutex.
Saya punya meja dengan ~ 14 juta catatan. Jika saya ingin menambahkan lebih banyak data dalam format yang sama, apakah ada cara untuk memastikan catatan yang ingin saya masukkan tidak ada tanpa menggunakan sepasang kueri (yaitu, satu permintaan untuk memeriksa dan satu untuk memasukkan adalah hasil yang ditetapkan adalah kosong)?
Apakah unique
batasan pada bidang menjamin insert
kehendak gagal jika sudah ada?
Tampaknya dengan hanya kendala, ketika saya mengeluarkan insert via php, skripnya serak.
mysql
sql
primary-key
sql-insert
warren
sumber
sumber
Jawaban:
menggunakan
INSERT IGNORE INTO table
lihat http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
ada juga
INSERT … ON DUPLICATE KEY UPDATE
sintaks, Anda dapat menemukan penjelasan di dev.mysql.comPosting dari bogdan.org.ua sesuai dengan cache web Google :
sumber
INSERT … ON DUPLICATE KEY UPDATE
lebih baik karena tidak menghapus baris, menjagaauto_increment
kolom dan data lainnya.INSERT … ON DUPLICATE KEY UPDATE
metode tidak menambah kolom AUTO_INCREMENT apa pun dengan gagal memasukkan. Mungkin karena itu tidak benar-benar gagal, tetapi DIPERBARUI.Larutan:
Penjelasan:
Permintaan terdalam
digunakan sebagai
WHERE NOT EXISTS
-condition mendeteksi jika sudah ada baris dengan data yang akan dimasukkan. Setelah satu baris dari jenis ini ditemukan, kueri mungkin berhenti, karenanyaLIMIT 1
(optimasi mikro, dapat dihilangkan).Kueri perantara
mewakili nilai yang akan dimasukkan.
DUAL
merujuk ke satu baris khusus, satu tabel kolom hadir secara default di semua database Oracle (lihat https://en.wikipedia.org/wiki/DUAL_table ). Pada MySQL-Server versi 5.7.26 saya mendapat permintaan yang valid ketika menghilangkanFROM DUAL
, tetapi versi yang lebih lama (seperti 5.5.60) tampaknya memerlukanFROM
informasi. Dengan menggunakanWHERE NOT EXISTS
kueri perantara, mengembalikan hasil kosong yang disetel jika kueri paling dalam menemukan data yang cocok.Kueri luar
menyisipkan data, jika ada yang dikembalikan oleh kueri perantara.
sumber
INSERT IGNORE
danINSERT ON DUPLICATE KEY
memerlukan batasan kunci unik)stuff for value1
danstuff for value2
identik? Ini akan melemparDuplicate column name
SELECT 1
daripadaSELECT *
di subqueries. Jauh lebih mungkin bahwa ini dapat dipenuhi oleh indeks.pada pembaruan kunci rangkap , atau masukkan abaikan dapat menjadi solusi yang layak dengan MySQL.
Contoh tentang pembaruan pembaruan kunci duplikat berdasarkan mysql.com
Contoh memasukkan abaikan berdasarkan mysql.com
Atau:
Atau:
sumber
Kendala sederhana apa pun harus dilakukan, jika pengecualian dapat diterima. Contoh:
Maaf apakah ini tampak sederhana. Saya tahu itu terlihat buruk dihadapkan pada tautan yang Anda bagikan dengan kami. ;-(
Tapi saya tetap memberikan jawaban ini, karena sepertinya memenuhi kebutuhan Anda. (Jika tidak, ini dapat memicu Anda memperbarui persyaratan Anda, yang juga akan menjadi "Hal yang Baik" (TM)).
Diedit : Jika sebuah insert akan merusak batasan unik basis data, sebuah pengecualian dilemparkan ke tingkat basis data, diteruskan oleh driver. Itu pasti akan menghentikan skrip Anda, dengan kegagalan. Harus dimungkinkan dalam PHP untuk mengatasi kasus itu ...
sumber
INSERT IGNORE
pada dasarnya mengubah semua kesalahan menjadi peringatan sehingga skrip Anda tidak terganggu. Anda kemudian dapat melihat peringatan apa pun dengan perintahSHOW WARNINGS
. Dan catatan penting lainnya : kendala UNIK tidak bekerja dengan nilai NULL, yaitu. row1 (1, NULL) dan row2 (1, NULL) keduanya akan dimasukkan (kecuali kendala lain seperti kunci utama rusak). DisayangkanBerikut adalah fungsi PHP yang akan menyisipkan baris hanya jika semua nilai kolom yang ditentukan belum ada dalam tabel.
Jika salah satu kolom berbeda, baris akan ditambahkan.
Jika tabel kosong, baris akan ditambahkan.
Jika ada baris di mana semua kolom yang ditentukan memiliki nilai yang ditentukan, baris tersebut tidak akan ditambahkan.
Contoh penggunaan:
sumber
mysql_*
ekstensi sudah ditinggalkan pada PHP 5.5.0, dan telah dihapus pada PHP 7.0.0. Sebaliknya, ekstensi mysqli atau PDO_MySQL harus digunakan. Lihat juga Ikhtisar API MySQL untuk bantuan lebih lanjut saat memilih API MySQL.Jika catatan ada, itu akan ditimpa; jika belum ada, itu akan dibuat.
sumber
REPLACE
dapat menghapus baris dan kemudian memasukkan alih-alih pembaruan. Efek sampingnya adalah bahwa kendala dapat menghapus objek lain dan menghapus pemicu dipecat.Coba yang berikut ini:
sumber
Ada beberapa jawaban yang mencakup cara mengatasi ini jika Anda memiliki
UNIQUE
indeks yang dapat Anda periksa denganON DUPLICATE KEY
atauINSERT IGNORE
. Itu tidak selalu terjadi, dan karenaUNIQUE
memiliki batasan panjang (1000 byte) Anda mungkin tidak dapat mengubahnya. Misalnya, saya harus bekerja dengan metadata di WordPress (wp_postmeta
).Saya akhirnya menyelesaikannya dengan dua pertanyaan:
Kueri 1 adalah
UPDATE
kueri reguler tanpa efek ketika dataset yang dimaksud tidak ada. Kueri 2 adalahINSERT
yang tergantung pada aNOT EXISTS
, yaituINSERT
hanya dieksekusi ketika dataset tidak ada.sumber
Sesuatu yang perlu dicatat adalah bahwa INSERT IGNORE masih akan menambah kunci utama apakah pernyataan itu sukses atau tidak seperti INSERT biasa.
Ini akan menyebabkan celah pada kunci utama Anda yang mungkin membuat seorang programmer tidak stabil secara mental. Atau jika aplikasi Anda dirancang dengan buruk dan tergantung pada kunci primer tambahan yang sempurna, itu mungkin menjadi sakit kepala.
Lihat ke dalam
innodb_autoinc_lock_mode = 0
(pengaturan server, dan datang dengan sedikit performa), atau gunakan SELECT terlebih dahulu untuk memastikan permintaan Anda tidak akan gagal (yang juga datang dengan kinerja dan kode tambahan).sumber
SELECT
kekalahan seluruh tujuan hanya menyerahkan batch besarINSERT
dan tidak ingin khawatir tentang duplikat.Perbarui atau masukkan tanpa kunci utama yang diketahui
Jika Anda sudah memiliki kunci utama atau unik, jawaban yang lain dengan salah satu
INSERT INTO ... ON DUPLICATE KEY UPDATE ...
atauREPLACE INTO ...
harus berfungsi dengan baik (perhatikan bahwa ganti menjadi dihapus jika ada dan kemudian sisipkan - dengan demikian tidak memperbarui sebagian nilai yang ada).Tetapi jika Anda memiliki nilai untuk
some_column_id
dansome_type
, kombinasi yang dikenal unik. Dan Anda ingin memperbaruisome_value
jika ada, atau masukkan jika tidak ada. Dan Anda ingin melakukannya hanya dalam satu permintaan (untuk menghindari menggunakan transaksi). Ini mungkin solusi:Pada dasarnya, kueri mengeksekusi dengan cara ini (tidak sesulit kelihatannya):
WHERE
pencocokan klausa.s
), di mana nilai kolom secara eksplisit diberikan (s.id adalah NULL, sehingga akan menghasilkan pengidentifikasi kenaikan otomatis baru).s
akan dibuang (karena LIMIT 1 pada tabelt
), dan itu akan selalu memicuON DUPLICATE KEY
yang akanUPDATE
menjadisome_value
kolom.s
).Catatan: Setiap tabel dalam database relasional harus memiliki setidaknya
id
kolom kenaikan otomatis utama . Jika Anda tidak memiliki ini, tambahkan, bahkan ketika Anda tidak membutuhkannya pada pandangan pertama. Pasti diperlukan untuk "trik" ini.sumber
INSERT INTO ... SELECT FROM
format. Kenapa kamu juga?INSERT INTO... SELECT FROM...
solusi biasa . Silakan merujuk kepada saya tautan ke jawaban yang sama, jika Anda dapat menemukannya saya akan menghapus jawaban ini, jika tidak, Anda membatalkan jawaban saya (kesepakatan?). Pastikan untuk memverifikasi bahwa jawaban yang akan Anda tautkan hanya menggunakan 1 kueri (untuk pembaruan + sisipan), tidak ada transaksi, dan mampu menargetkan kombinasi kolom yang dikenal unik (jadi, secara terpisah kolom tidak harus unik).