MySQL Otomatik artış alanları kendiliğinden sıfırlanır


12

INT (11) olarak ayarlanmış otomatik artan bir alana sahip bir MySQL tablonuz var. Bu tablo hemen hemen bir uygulamada çalışan işlerin bir listesini saklar. Uygulamanın ömrü boyunca herhangi bir anda, tablo binlerce giriş içerebilir veya tamamen boş olabilir (yani her şey bitmiştir).

Alan başka hiçbir şeye yabancı anahtarlı değildir.

Sıfırlama işlemini hiç yakalayamamış olsak da, otomatik artış kendisini rastgele sıfıra sıfırlıyor gibi görünüyor.

Sorun belirginleşiyor çünkü otomatik artış alanının 600.000 kayda kadar çıktığını görüyoruz ve bir süre sonra otomatik artış alanının düşük 1000'lerde çalıştığı görülüyor.

Neredeyse tablo boşsa otomatik artış kendisini sıfırlar gibi.

Bu mümkün mü ve eğer öyleyse, nasıl kapatabilirim veya sıfırlama şeklini nasıl değiştirebilirim?

Değilse, neden bunu yaptığını açıklayan var mı?

Teşekkürler!


MySQL'in hangi sürümü? İşlemler veya çoğaltma kullanılıyor mu?
18'de incele

Yanıtlar:


27

Otomatik artış sayacı diskte değil, yalnızca ana bellekte saklanır.

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

Bu nedenle, hizmet (veya sunucu) yeniden başlatıldığında aşağıdakiler gerçekleşir:

Bir sunucu başlattıktan sonra, t tablosuna ilk ekleme için, InnoDB bu ifadenin eşdeğerini çalıştırır: SELECT MAX (ai_col) FROM t FOR UPDATE;

InnoDB deyim tarafından alınan değeri bir arttırır ve bunu sütuna ve tablonun otomatik artış sayacına atar. Tablo boşsa, InnoDB 1 değerini kullanır.

Yani basit İngilizce'de, MySQL hizmeti başladıktan sonra tablonuz için otomatik artış değerinin ne olması gerektiği hakkında hiçbir fikri yoktur. Bu nedenle, ilk satır eklediğinizde, otomatik artış kullanan alanın maksimum değerini bulur, bu değere 1 ekler ve elde edilen değeri kullanır. Satır yoksa, 1'den başlar.

Kullanıcıların üçüncü taraf ödeme sitesine yönlendirildikleri çok iş parçacıklı bir ortamda kimlikleri düzgün bir şekilde yönetmek için tabloyu ve mysql'in otomatik artış özelliğini kullandığımız için bu bizim için bir sorundu. Bu nedenle, üçüncü tarafın bize gönderdiği ve bize geri gönderdiği kimliğin benzersiz olduğundan ve bu şekilde kalacağından emin olmak zorunda kaldık (ve elbette, kullanıcının yönlendirildikten sonra işlemi iptal etme olasılığı vardır).

Bu nedenle, bir satır oluşturuyor, oluşturulan otomatik artış değerini elde ediyor, tabloyu temiz tutmak için satırı siliyor ve değeri ödeme sitesine yönlendiriyoruz. InnoDB'nin AI değerlerini işleme biçimini gidermek için yaptığımız şey şuydu:

$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); 

Bu, her zaman gereksiz yere tablo havaya uçurmadan oluşturulan bir satırda oluşturulan en son işlemId tutar.

Umarım bu durumla karşılaşabilecek herkese yardımcı olur.

Düzenleme (2018-04-18) :

Aşağıda belirtildiği gibi, bunun davranışı MySQL 8.0+ ile değiştirilmiş gibi görünüyor.

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

Bu çalışma günlüğündeki ifadeler en iyi şekilde hatalıdır, ancak bu yeni sürümlerde InnoDB'nin artık yeniden başlatmalarda kalıcı autoinc değerlerini desteklediği görülmektedir.

-Gremio


İlk yazı için fena değil dostum. +1.
ceejayoz

Orada bilgi biraz tatlı Gremio. Teşekkürler!! Bunu tamamen ertelemiştim ve sorunu dahili olarak daha sonraki bir tarihte gözden geçirilecek bir şey olarak arşivledim, ancak geri dönerek çözümünüz bir cazibe çalışıyor!
Ocak'taki Hooligancat

3

Bu sorunu yaşadık ve optimizasyon tablosu boş bir tabloda çalıştırıldığında, otomatik artış değerinin de sıfırlandığını keşfettik. Bu MySQL hata raporuna bakın .

Çözüm olarak şunları yapabilirsiniz:

ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;

Bunun yerine OPTIMIZE TABLE.

Görünüşe göre MySQL dahili olarak bunu yapıyor (Açıkça Otomatik artış değerini ayarlamadan)


2

Sadece karanlıkta bir çekim - uygulama TRUNCATE TABLEişlemi tamamlandığında tabloyu boşaltmak için a kullanıyorsa , otomatik artış alanını sıfırlar. İşte soru hakkında kısa bir tartışma . Her ne kadar bu bağlantı InnoDB'nin bir trunk üzerindeki otomatik_kullanımları sıfırlamadığını belirtmesine rağmen, bu bir hata olarak bildirildi ve birkaç yıl önce düzeltildi.

Tahminimin doğru olduğunu varsayarsak, sorunu çözmek için kısalmadan silmeye geçebilirsiniz.


TRUNCATE kullandığımızı düşünmedim, ama emin olmak için kontrol etmek zorunda kaldık. Hatta emin olmak için PHP sürücü seviyesine doğrulamak için şimdiye kadar gitti. BU değildik. Yine de olası çözümü takdir edin.
Hooligancat

1

Yalnızca bu değerin açık bir şekilde sıfırlanması veya o alanın bırakılması / yeniden oluşturulması veya benzer başka bir şiddetli işlem, otomatik_arama sayacını sıfırlamalıdır. (TRUNCATE gerçekten iyi bir teoriydi.) Tanık olduğunuz son değer sadece 600k olduğunda aniden 32 bit INT'yi sarmanız imkansız görünüyor. Tablonun boşalması nedeniyle kesinlikle sıfırlanmamalıdır. PHP kodunuzda mysql hatası ya da başka bir şey var. Ya da yanındaki kapıdaki adam sana bir numara oynuyor.

İkili günlüğü açarak hata ayıklayabilirsiniz , çünkü aşağıdaki gibi ifadeler içerecektir:

SET INSERT_ID=3747670/*!*/;

Sonra en azından sayaç sıfırlanmadan hemen önce de dahil olmak üzere, o tabloya olanların her ayrıntısını görebilirsiniz.


hata ayıklama ipucu için teşekkürler. Bir Serverfault check-in gerektiğinden bir süre oldu ve bahşiş takdir
Hooligancat

0

ALTER TABLE tablo_adı ENGINE = MyISAM

Benim için çalışıyor. Masamız her zaman çok küçük tutulur, bu nedenle InnoDB'ye gerek yoktur.


İşlemlere mi ihtiyacınız var?
Anthony Rutledge

0

InnoDB otomatik artış değerini diskte saklamaz, bu nedenle MySQL sunucusu kapatıldığında değeri unutur. MySQL yeniden başlatıldığında, InnoDB'nin motoru otomatik artış değerini bu şekilde geri yükler: SELECT (MAX(id) + 1) AS auto_increment FROM table. Bu, MySQL sürüm 8.0 ile giderilen bir hatadır .

Sorunu çözmek için tablo motorunu değiştirin:

ALTER TABLE table ENGINE = MyISAM

Veya yayımlandığında MySQL sunucusunu 8.0 sürümüne güncelleyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.