Bidang kenaikan-otomatis MySQL diatur ulang dengan sendirinya

12

Kami memiliki tabel MySQL yang memiliki bidang penambahan otomatis ditetapkan sebagai INT (11). Tabel ini cukup banyak menyimpan daftar pekerjaan yang berjalan dalam suatu aplikasi. Pada saat tertentu selama masa aplikasi, tabel bisa berisi ribuan entri atau benar-benar kosong (yaitu semuanya telah selesai).

Bidang ini tidak memiliki kunci asing untuk hal lain.

Peningkatan otomatis tampaknya secara otomatis me-reset sendiri ke nol, meskipun kami tidak pernah benar-benar dapat menjebak reset.

Masalahnya menjadi jelas karena kita melihat bidang kenaikan otomatis bangun, katakanlah, 600.000 rekaman atau lebih dan kemudian beberapa saat kemudian bidang kenaikan otomatis tampaknya berjalan di 1000 rendah.

Hampir seolah-olah kenaikan otomatis me-reset sendiri jika tabel kosong.

Apakah ini mungkin dan jika ya, bagaimana cara mematikannya atau mengubah cara pengaturannya?

Jika tidak, apakah ada yang punya alasan mengapa melakukan ini?

Terima kasih!

Hooligancat
sumber
Apa versi MySQL? Apakah transaksi atau replikasi sedang digunakan?
thinice

Jawaban:

26

Penghitung kenaikan otomatis disimpan hanya di memori utama, bukan pada disk.

http://dev.mysql.com/doc/refman/4.1/en/innodb-auto-increment-handling.html

Karena hal ini ketika layanan (atau server) restart maka hal berikut akan terjadi:

Setelah server dinyalakan, untuk penyisipan pertama ke tabel t, InnoDB mengeksekusi yang setara dengan pernyataan ini: SELECT MAX (ai_col) DARI t UNTUK PEMBARUAN;

InnoDB menambah satu nilai yang diambil oleh pernyataan dan menugaskannya ke kolom dan ke penghitung kenaikan otomatis untuk tabel. Jika tabel kosong, InnoDB menggunakan nilai 1.

Jadi, dalam bahasa Inggris yang sederhana, setelah layanan MySQL dimulai, tidak tahu berapa nilai kenaikan otomatis untuk tabel Anda. Jadi ketika Anda pertama kali menyisipkan baris, ia menemukan nilai maksimum bidang yang menggunakan kenaikan otomatis, menambahkan 1 ke nilai ini, dan menggunakan nilai yang dihasilkan. Jika tidak ada baris, itu akan mulai dari 1.

Ini merupakan masalah bagi kami, karena kami menggunakan tabel dan fitur penambahan otomatis mysql untuk mengelola ID dengan rapi di lingkungan multi-utas tempat pengguna diarahkan kembali ke situs pembayaran pihak ketiga. Jadi kami harus memastikan ID pihak ketiga yang didapat dan dikirim kembali kepada kami adalah unik dan akan tetap seperti itu (dan tentu saja ada kemungkinan pengguna akan membatalkan transaksi setelah mereka dialihkan).

Jadi kami membuat baris, memperoleh nilai kenaikan-otomatis yang dihasilkan, menghapus baris agar tabel tetap bersih, dan meneruskan nilai ke situs pembayaran. Apa yang akhirnya kami lakukan untuk memperbaiki masalah cara InnoDB menangani nilai-nilai AI adalah sebagai berikut:

$query = "INSERT INTO transactions_counter () VALUES ();";
mysql_query($query);
$transactionId = mysql_insert_id();
$previousId = $transactionId - 1;
$query = "DELETE FROM transactions_counter WHERE transactionId='$previousId';";
mysql_query($query); 

Ini selalu membuat transactionId terbaru dihasilkan sebagai baris dalam tabel, tanpa perlu meledakkan tabel.

Semoga itu bisa membantu orang lain yang mungkin mengalami ini.

Edit (2018-04-18) :

Seperti yang disebutkan Finesse di bawah ini, kelihatannya perilaku ini telah dimodifikasi di MySQL 8.0+.

https://dev.mysql.com/worklog/task/?id=6204

Kata-kata dalam worklog itu paling buruk, namun tampaknya InnoDB di versi yang lebih baru sekarang mendukung nilai autoinc yang persisten di seluruh reboot.

-Gremio

Gremio
sumber
Lumayan untuk posting pertama, kawan. +1.
ceejayoz
Sedikit pengetahuan manis di sana Gremio. Terima kasih!! Saya telah benar-benar menundanya dan mengarsipkan masalah ini secara internal sebagai sesuatu untuk ditinjau di kemudian hari, tetapi kembali ke sana bahwa solusi Anda sangat mempesona!
Hooligancat
3

Kami telah mengalami masalah ini dan telah menemukan bahwa ketika tabel optimal dijalankan pada tabel kosong, nilai kenaikan otomatis juga direset. Lihat laporan bug MySQL ini .

Sebagai solusinya, Anda dapat melakukan:

ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;

Alih-alih OPTIMIZE TABLE.

Sepertinya inilah yang dilakukan MySQL secara internal (tanpa menetapkan nilai kenaikan otomatis, jelas)

tongkat
sumber
2

Hanya bidikan dalam gelap - jika aplikasi menggunakan TRUNCATE TABLEuntuk mengosongkan tabel saat selesai diproses, itu akan mengatur ulang bidang kenaikan-otomatis. Berikut ini adalah diskusi singkat tentang pertanyaan itu. Meskipun tautan itu menyebutkan bahwa InnoDB tidak menyetel ulang auto_increments pada trunc, itu dilaporkan sebagai bug dan diperbaiki beberapa tahun lalu.

Dengan asumsi dugaan saya benar, Anda dapat mengubah dari memotong ke menghapus untuk memperbaiki masalah.

dsolimano
sumber
Saya tidak berpikir kami menggunakan TRUNCATE, tetapi kami harus memeriksa untuk memastikan. Bahkan melangkah sejauh memverifikasi ke tingkat driver PHP untuk memastikan. Tapi kami tidak. Hargai solusi yang mungkin.
Hooligancat
1

Hanya setel ulang nilai itu secara eksplisit, atau setetes / buat ulang bidang itu, atau operasi kekerasan serupa lainnya yang akan mengatur ulang penghitung auto_increment. (The TRUNCATE adalah teori yang sangat bagus.) Tampaknya tidak mungkin Anda tiba-tiba membungkus INT 32-bit ketika nilai terakhir yang Anda saksikan hanya 600k. Ini pasti tidak seharusnya direset hanya karena meja kosong. Anda juga memiliki bug mysql atau sesuatu di kode PHP Anda. Atau pria di bilik sebelah sedang mempermainkanmu.

Anda bisa melakukan debug dengan menyalakan log biner , karena akan berisi pernyataan seperti ini di seluruh:

SET INSERT_ID=3747670/*!*/;

Maka setidaknya Anda dapat melihat setiap detail dari apa yang terjadi pada tabel itu, termasuk tepat sebelum penghitung ulang.

IcarusNM
sumber
terima kasih atas tip debugnya. Sudah lama sejak saya perlu memeriksa Serverfault dan saya menghargai tip Anda
Hooligancat
0

ALTER TABLE table_name ENGINE = MyISAM

Bekerja untukku. Meja kami selalu disimpan sangat kecil, jadi tidak perlu untuk InnoDB.

QuickFix
sumber
Apakah Anda perlu transaksi?
Anthony Rutledge
0

InnoDB tidak menyimpan nilai kenaikan otomatis pada disk sehingga lupa ketika server MySQL dimatikan. Ketika MySQL dimulai lagi, mesin InnoDB mengembalikan nilai auto increment cara ini: SELECT (MAX(id) + 1) AS auto_increment FROM table. Ini adalah bug yang diperbaiki di MySQL versi 8.0.

Ubah engine meja untuk memecahkan masalah:

ALTER TABLE table ENGINE = MyISAM

Atau perbarui server MySQL ke versi 8.0 saat dirilis.

Kemahiran
sumber