“Kilit bekleme zaman aşımı aşıldı; işlemi yeniden başlatmayı deneyin. "


267

Aşağıdaki MySQL UPDATEdeyimini çalıştırıyorum :

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Bir işlem kullanmıyorum, neden bu hatayı alıyorum? Hatta MySQL sunucumu yeniden başlatmayı denedim ve yardımcı olmadı.

Tabloda 406.733 satır vardır.

Yanıtlar:


211

Bir işlem kullanıyorsunuz; autocommit işlemleri devre dışı bırakmaz, sadece ifadenin sonunda otomatik olarak taahhütte bulunur.

Ne oluyor, başka bir iş parçacığı çok uzun süre bazı kayıtlarda bir kayıt kilidi tutuyor (tablodaki her kaydı güncelleştiriyorsunuz!) Ve iş parçacığınız zaman aşımına uğruyor.

Bir etkinlik düzenleyerek etkinliğin daha fazla ayrıntısını görebilirsiniz.

SHOW ENGINE INNODB STATUS

etkinlikten sonra ( sqleditörde). İdeal olarak bunu sessiz bir test makinesinde yapın.


1
Çıktıyı bir dosyaya kaydetmenin bir yolu var mı? SHOW ENGINE INNODB STATUS \ G> innodb_stat.txt dosyasını denedim, ancak çalışmıyor.
yantaq

14
Komut satırından: mysql [kimlik bilgilerini ekleyin] -e "MOTOR GİRİŞİNİ GÖSTER" DURUMU \ G "> innodb_stat.txt
VenerableAgents

birçok mysql iş parçacığı (veya işlem) meşgul, örneğin bazı sorgu çok uzun zamana ihtiyaç duyar, bu yüzden bazı processboşta beklemek zorunda . Eğer öyleyse bu hatayı alabilirsiniz. Haklı mıyım?
zhuguowei

6
Tek bir işlem sırasında aynı satırda birden çok (2+) UPDATE sorgusu çalıştırmak da bu hataya neden olur.
Okneloper

Python MySQL Connector kullananlar connection.commit()için taahhüt için kullanın INSERTya da UPDATEsadece üzerinden vurdu.
AER

334

MySQL'de kilitli tablolar için KİLİT AÇMA KUVVETLERİ:

Bunun gibi kilitlerin kırılması , veritabanındaki atomisitenin kilide neden olan sql ifadelerinde uygulanmamasına neden olabilir.

Bu hackish ve doğru çözüm kilitlere neden olan uygulamanızı düzeltmektir. Bununla birlikte, dolar hatta olduğunda, hızlı bir vuruş bir şeyler tekrar hareket ettirir.

1) MySQL girin

mysql -u your_user -p

2) Kilitli tabloların listesini görelim

mysql> show open tables where in_use>0;

3) Mevcut işlemlerin listesini görelim, bunlardan biri tablolarınızı kilitliyor

mysql> show processlist;

4) Bu işlemlerden birini öldürün

mysql> kill <put_process_id_here>;

14
Bu tehlikeli ve acayip. Uygun bir çözüm uygulamanızı düzeltmektir.
Zenexer

71
Saçmalık, bu bir karmaşayı geri almanıza ve ardından uygulamayı düzeltmenize izin verir. ŞİMDİ düzeltmek zorunda bu konu için bu adama 100 kadar oy verebilir olsaydım.
Lizardx

7
Lizardx'a katılıyorum. MOTOR GİRİŞ DURUMU
Travis Schneeberger

8
Uzun süredir devam eden bir sorguyu bu şekilde öldürmek nasıl tehlikelidir ? Arayan istemci sadece bir hata alır.
Xeoncross

7
Ben puanı almak @EricLeschinski ama dünyada sizin gibi bir özensiz veritabanı neden kullanacağınızı sormak zorunda MySQL bir on Yaşam Kritik sistemde?
Xeoncross

96
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

Şimdi kilidi tekrar başlatın. SHOW ENGINE INNODB STATUS\GVeritabanına bir tane vermek ve diğer hangi işlemin sizinkini kilitlediğini görmek için 100 saniyeniz var .


8
Bu cevap, askerin neden hata aldığını açıklamaz. Sadece cevabı vermenin yanı sıra nedenini açıklayabilir misiniz?
Kızak

5
+1 bu soruyu doğrudan yanıtlamasa da, benim için bu soruna geçici bir çözüm bulmak için iyi bir referans.
Jossef Harush

1
@ArtB dev.mysql.com/doc/innodb/1.1/en/… Temelde OP hatayı alıyor çünkü masaya bir kilit çağrıldı ve işlemi sonlandırmadan önce geçen süre lock_wait_timeoutdeğeri aştı
fyrye

70

Veritabanınız iyi ayarlanmışsa bir göz atın. Özellikle işlem izolasyonu. İnnodb_lock_wait_timeout değişkenini artırmak iyi bir fikir değil.

MySQL CL'de veritabanı işlem yalıtım düzeyinizi kontrol edin:

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

Yalıtım düzeyini değiştirerek iyileştirmeler elde edebilirsiniz, REPE COMMITTED yerine REPEATABLE READ (InnoDB Defaults) kullanın

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

Ayrıca SELECT FOR UPDATE'i yalnızca gerekli olduğunda kullanmayı deneyin.


1
Bu, kilitleme sorunları için mükemmel bir çözümdür.
redolent

3
Benim için harika çalışıyor, my.cnf sürümü [mysqld] transaction-isolation = READ-COMMITTED
Benoit Gauthier

Sadece bir not: MySQL 8 tx_isolationdeğişkeni olarak yeniden adlandırdı transaction_isolation.
xonya

Bununla birlikte, okuma izolasyonundan OKULMAYA DEVAM ET seçeneğine geçiş yaptığınızda nelere maruz kaldığınızı bilmeniz gerekir. Sonunda kaçınmak isteyebileceğiniz kirli veriler elde edebilirsiniz. Vikipedi İzolasyon
huggie

27

Önerilen çözümlerin hiçbiri benim için çalışmadı ama bu işe yaradı.

Sorgunun yürütülmesini engelleyen bir şey var. Büyük olasılıkla sorgunuzdaki tablolardan birini güncelleme, ekleme veya silme işleminden başka bir sorgu. Bunun ne olduğunu bulmalısınız:

SHOW PROCESSLIST;

Engelleme işlemini bulduktan sonra, işlemi bulun idve çalıştırın:

KILL {id};

İlk sorgunuzu yeniden çalıştırın.


SHOW PROCESSLIST ile listelenen tüm işlemleri yanlışlıkla öldürdüm; Şimdi phpmyadmin'de 500 hata alıyorum. Bu 500 hata bu süreçleri öldürmeyle ilgili mi? Evetse, nasıl yeniden başlatabilirim.
Dashrath

Neyi tanımladığınızı görebiliyorum, ancak süreci öldürmek işe yaramıyor. İşlem 'komutu "öldürülür", ancak işlem listesinde kalır.
Torsten

12

MarkR'ın söyledikleriyle% 100. autocommit her ifadeyi tek bir ifade işlemi yapar.

SHOW ENGINE INNODB STATUSkilitlenme nedeni hakkında bazı ipuçları vermelisiniz. Başka hangi tablo sorgulama görmek için yavaş sorgu günlüğünüze iyi bir göz atın ve tam bir tablescan yapan bir şey kaldırmaya çalışın. Satır düzeyinde kilitleme iyi çalışır, ancak tüm satırları kilitlemeye çalıştığınızda değil!


5

Bu tablodaki başka bir kaydı güncelleyebilir misiniz, yoksa bu tablo yoğun olarak kullanılıyor mu? Ne düşünüyorum, bu kaydı güncelleştirmek için gereken bir kilit elde etmeye çalışırken ayarlanan zaman aşımı zaman aşımına uğramış olmasıdır. Size yardımcı olabilecek zamanı artırabilirsiniz.


3
belki innodb_lock_wait_timeoutdemy.cnf
oblig

1
My.cnf içinde ayarladım: <br/> innodb_lock_wait_timeout = 120 <br/> MySQL 5.5 için varsayılan 50'dir. Bu değişiklikten sonra birim testlerimde bu sorunu göremedim! Bu proxool'dan tomcat jdbc havuzuna geçtikten sonra oldu. Muhtemelen tomcat havuzu ile daha fazla işlem süresi nedeniyle ?!
Champ

3

Satır sayısı çok büyük değil ... Birincil anahtar değilse account_import_id'de bir dizin oluşturun.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);

OMG ... bu beni kurtardı. Bir üretim DB'sini bir indeks bırakarak kraliyetle vidaladım ve bu düzeltti. Teşekkürler.
Nick Gotch

2

Büyük bir sorguyu henüz öldürdüyseniz, rollback . Öldürülen sorgu geri alınmadan önce başka bir sorgu çıkarırsanız, kilit zaman aşımı hatası alabilirsiniz. Bana böyle oldu. Çözüm sadece biraz beklemekti.

Detaylar:

Yaklaşık 1 milyon satırdan yaklaşık 900.000'i kaldırmak için bir DELETE sorgusu yayınladım.

Bunu yanlışlıkla çalıştırdım (satırların yalnızca% 10'unu kaldırır): DELETE FROM table WHERE MOD(id,10) = 0

Bunun yerine (satırların% 90'ını kaldırır): DELETE FROM table WHERE MOD(id,10) != 0

Satırların% 90'ını değil,% 90'ını kaldırmak istedim. Bu yüzden MySQL komut satırındaki işlemi, şimdiye kadar silmiş olduğu tüm satırları geri alacağını bilerek öldürdüm.

Sonra hemen doğru komutu çalıştırdım ve lock timeout exceededkısa süre sonra bir hata aldım . Kilit aslında rollbackarka planda hala öldürülen sorgu olabilir olduğunu fark ettim . Bu yüzden birkaç saniye bekledim ve sorguyu yeniden çalıştırdım.


1

Veritabanı tablolarının InnoDB depolama motoru ve READ-COMMITTED işlem yalıtım düzeyini kullandığından emin olun.

SELECT @@ GLOBAL.tx_isolation, @@ tx_isolation; mysql konsolunda.

READ-COMMITTED olarak ayarlanmamışsa, ayarlamanız gerekir. Ayarlamadan önce mysql'de SUPER ayrıcalıklarına sahip olduğunuzdan emin olun.

Http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html adresinden yardım alabilirsiniz. .

Bunu ayarlayarak, sorunun çözüleceğini düşünüyorum.


Ayrıca, bunu bir kerede iki işlemde güncellemeye çalışmadığınızı kontrol etmek isteyebilirsiniz. Kullanıcılar (@tala) bu bağlamda benzer hata mesajlarıyla karşılaştı, belki ...


1

Google'dan geldim ve benim için işe yarayan çözümü eklemek istedim. Benim sorunum ben OP ile aynı hatayı aldım bu yüzden basamaklı FK bir sürü vardı büyük bir tablo kayıtlarını silmek çalışıyordu oldu.

Devre dışı bıraktım autocommitve sadece ekleyerek çalıştıCOMMIT SQL cümle sonunda . Anladığım kadarıyla bu, komutun sonunda beklemek yerine tamponu yavaş yavaş serbest bırakır.

OP örneğine devam etmek için, bu işe yaramış olmalıydı:

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

autocommitMySQL yapılandırmasını daha önce olduğu gibi bırakmak istiyorsanız tekrar etkinleştirmeyi unutmayın .

mysql> set autocommit=1;


0

Partiye geç (her zamanki gibi) ancak benim sorunum bazı kötü SQL (acemi olmak) yazmıştı ve çeşitli süreçlerin kayıt (lar) üzerinde bir kilit vardı <- emin değil verbiage. Sonunda sadece: SHOW PROCESSLISTve sonra kimlikleri kullanarak öldürmek zorunda kaldımKILL <id>


0

Ben php dil ​​yapı çıkış kullanırken bu tür bir şey başıma geldi; işlemin ortasında. Sonra bu işlem "askıda kalıyor" ve mysql işlemini (işlem listesi ile yukarıda açıklanmıştır;)


0

Benim durumumda, verileri düzeltmek için anormal bir sorgu çalıştırıyordum. Sorgunuzdaki tabloları kilitlerseniz Kilitleme zaman aşımı ile uğraşmanıza gerek kalmaz:

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

Bu muhtemelen normal kullanım için iyi bir fikir değildir.

Daha fazla bilgi için, bkz: MySQL 8.0 Başvuru Kılavuzu


0

Ben işlemsel olmayan (önemli günlükler için) biri olan 2 Doktrin DBAL bağlantıları olan bu koştu, birbirlerine bağlı değil paralel çalıştırmak için tasarlanmıştır.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

Entegrasyon testlerim, çok testten sonra veri geri alma işlemlerine alındı.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

Benim çözüm bu testlerde sarma işlemini devre dışı bırakmak ve db verilerini başka bir şekilde sıfırlamak oldu.


-4

Ben sadece bir giriş ile bir tablo güncelleme olmasına rağmen, aynı hata vardı, ama mysql yeniden başlattıktan sonra, çözüldü.

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.