แก้ไข“ เกินกำหนดเวลารอการล็อคแล้ว ลองรีสตาร์ททรานแซคชัน” สำหรับตาราง Mysql ที่“ ติด” อยู่หรือไม่


131

จากสคริปต์ฉันส่งแบบสอบถามเช่นนี้หลายพันครั้งไปยังฐานข้อมูลท้องถิ่นของฉัน:

update some_table set some_column = some_value

ฉันลืมที่จะเพิ่มส่วนไหนดังนั้นคอลัมน์เดียวกันถูกตั้งค่าเป็นค่าเดียวกันสำหรับทุกแถวในตารางและทำได้หลายพันครั้งและคอลัมน์ถูกทำดัชนีดังนั้นดัชนีที่สอดคล้องกันอาจถูกปรับปรุงหลายครั้งเกินไป .

ฉันสังเกตเห็นสิ่งผิดปกติเพราะใช้เวลานานเกินไปดังนั้นฉันจึงฆ่าสคริปต์ ฉันรีบูตเครื่องคอมพิวเตอร์ของฉันตั้งแต่นั้นมา แต่มีบางอย่างติดอยู่ในตารางเนื่องจากข้อความค้นหาง่าย ๆ ใช้เวลานานมากในการรันและเมื่อฉันลองวางดัชนีที่เกี่ยวข้องมันล้มเหลวด้วยข้อความนี้:

Lock wait timeout exceeded; try restarting transaction

มันเป็นตาราง innodb ดังนั้นการทำธุรกรรมที่ติดอยู่อาจเป็นนัย ฉันจะแก้ไขตารางนี้และลบธุรกรรมที่ค้างอยู่ออกจากมันได้อย่างไร


3
อะไรคือผลลัพธ์ของSHOW FULL PROCESSLIST?
Wolph

มันแสดงเฉพาะคำสั่ง SHOW FULL PROCESSLIST ไม่มีอะไรอื่น มันเป็นฐานข้อมูลการพัฒนาท้องถิ่น ไม่มีอะไรทำงานอยู่ ฉันได้รับข้อความแจ้งข้อผิดพลาด 'lock wait .. ' ในบรรทัดคำสั่งเมื่อฉันลองวางดัชนีจากที่นั่น
ทอม

ในกรณีดังกล่าวคุณอาจสร้างการเชื่อมต่อ 2 รายการแยกกันในธุรกรรมที่แตกต่างกันซึ่งต้องรอแต่ละรายการ
Wolph

ฉันไม่ได้สร้างธุรกรรมใด ๆ ในภายหลัง ฉันฆ่าสคริปต์รีบูตเครื่องและเข้าสู่ระบบจากบรรทัดคำสั่งเพื่อดูรอบ ๆ ไม่มีอะไรใช้ฐานข้อมูลยกเว้นสำหรับไคลเอนต์บรรทัดคำสั่ง mysql ดังนั้นบางสิ่งต้องติดอยู่ในตาราง
Tom

คำตอบ:


143

ฉันมีปัญหาที่คล้ายกันและแก้ไขได้โดยการตรวจสอบกระทู้ที่กำลังทำงานอยู่ ในการดูเธรดที่กำลังรันให้ใช้คำสั่งต่อไปนี้ในอินเตอร์เฟสบรรทัดคำสั่ง mysql:

SHOW PROCESSLIST;

นอกจากนี้ยังสามารถส่งจาก phpMyAdmin หากคุณไม่มีสิทธิ์เข้าถึงอินเตอร์เฟสบรรทัดคำสั่ง mysql
สิ่งนี้จะแสดงรายการเธรดที่มีรหัสและเวลาในการดำเนินการที่สอดคล้องกันดังนั้นคุณสามารถฆ่าเธรดที่ใช้เวลาในการดำเนินการมากเกินไป ใน phpMyAdmin คุณจะมีปุ่มสำหรับหยุดเธรดโดยใช้ KILL ถ้าคุณใช้อินเตอร์เฟสบรรทัดคำสั่งให้ใช้คำสั่ง KILL ตามด้วย id ของเธรดเช่นในตัวอย่างต่อไปนี้:

KILL 115;

สิ่งนี้จะยุติการเชื่อมต่อสำหรับเธรดที่เกี่ยวข้อง


36
จดบันทึก! บางคนได้พูดถึงหัวข้อหนึ่งในหัวข้อ SO มากมายเกี่ยวกับปัญหานี้: บางครั้งกระบวนการที่ล็อกตารางจะปรากฏขึ้นขณะหลับในรายการกระบวนการ! ฉันฉีกผมออกจนฉันฆ่ากระทู้ทั้งหมดที่เปิดอยู่ในฐานข้อมูลที่เป็นปัญหานอนหลับหรือไม่ ในที่สุดก็ปลดล็อคตารางและปล่อยให้คิวรีอัปเดตทำงาน ผู้แสดงความคิดเห็นพูดถึงบางสิ่งบางอย่างเช่น "บางครั้งเธรดของ MySQL จะล็อกตารางจากนั้นก็พักในขณะที่รอสิ่งที่ไม่เกี่ยวข้องกับ MySQL เกิดขึ้น"
Eric L.

(ฉันเพิ่มคำตอบของฉันเองในการแยกส่วนความคิดที่นี่ออกจากคำถามที่เกี่ยวข้อง)
Eric L.

สิ่งนี้ช่วยฉัน ฉันมีเธรดการนอนสองสามตัวที่สร้างขึ้นโดยฟีเจอร์การจัดการ / สืบค้นฐานข้อมูล PHPStorm
Ejaz

ที่ดี! ฉันมีกระบวนการซ่อนเร้นตั้งแต่ 5 ชั่วโมงที่ฉันสามารถระบุและฆ่าได้
Aldo Paradiso

2
นี่ไม่ใช่วิธีการแก้ปัญหามากกว่าการพันเทปกาวบนแผลที่ติดเชื้อเป็นวิธีแก้ปัญหา คุณไม่ได้แก้ไขปัญหารากที่สำคัญ
user2914191

55

คุณสามารถตรวจสอบการทำธุรกรรมที่กำลังทำงานอยู่ด้วย

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`

ธุรกรรมของคุณควรเป็นหนึ่งในรายการแรกเนื่องจากเป็นรายการที่เก่าแก่ที่สุดในรายการ ตอนนี้เพียงแค่นำค่าจากtrx_mysql_thread_idและส่งKILLคำสั่ง:

KILL 1234;

หากคุณไม่แน่ใจว่าธุรกรรมใดเป็นของคุณให้ทำซ้ำแบบสอบถามแรกบ่อยๆและดูว่าธุรกรรมใดยังคงมีอยู่


คุณอาจจำเป็นต้องใช้บัญชีรูทเพื่อเรียกใช้ SQL นั้นเพื่อดูว่าธุรกรรมใดกำลังปิดกั้นการเข้าถึงข้อมูลอื่น ๆ จากตารางการใช้งานจริง ๆ
tom10271

40

ตรวจสอบสถานะ InnoDB สำหรับล็อค

SHOW ENGINE InnoDB STATUS;

ตรวจสอบ MySQL open tables

SHOW OPEN TABLES WHERE In_use > 0;

ตรวจสอบธุรกรรม InnoDB ที่รอดำเนินการ

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`; 

ตรวจสอบการพึ่งพาล็อค - บล็อกอะไร

SELECT * FROM `information_schema`.`innodb_locks`;

หลังจากตรวจสอบผลลัพธ์ข้างต้นแล้วคุณควรจะเห็นสิ่งที่ล็อคอยู่

สาเหตุของปัญหาอาจอยู่ในรหัสของคุณด้วยโปรดตรวจสอบฟังก์ชันที่เกี่ยวข้องโดยเฉพาะอย่างยิ่งสำหรับคำอธิบายประกอบหากคุณใช้ JPA เช่น Hibernate

ตัวอย่างเช่นที่อธิบายไว้ที่นี่การใช้คำอธิบายประกอบต่อไปนี้อย่างไม่ถูกต้องอาจทำให้เกิดการล็อคในฐานข้อมูล:

@Transactional(propagation = Propagation.REQUIRES_NEW) 

4
ขอบคุณมาก! เล่นSELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idเปิดเผยผู้ร้าย: ด้ายล็อคมาจากของฉันที่อยู่ IP ... ผมลืมที่จะปิดคอนโซลการแก้ปัญหาที่ผมได้ออกในช่วงกลางของการทำธุรกรรม ...
อีเลียส STREHLE

40

สิ่งนี้เริ่มเกิดขึ้นกับฉันเมื่อขนาดฐานข้อมูลของฉันเพิ่มขึ้นและฉันทำธุรกรรมมากมายกับมัน

ความจริงอาจมีวิธีการเพิ่มประสิทธิภาพแบบสอบถามของคุณหรือ DB ของคุณ แต่ลองใช้แบบสอบถาม 2 เหล่านี้เพื่อแก้ไขปัญหา

เรียกใช้สิ่งนี้:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

แล้วนี่:

SET innodb_lock_wait_timeout = 5000; 

2
ลิงค์อ้างอิง: innodb_lock_wait_timeout
culix

1
ฉันใช้ฐานข้อมูล 11GB ที่ยุ่งมาก นี่เป็นสิ่งเดียวที่ได้ผลสำหรับฉันขอบคุณ!
dongemus

เพียงจำไว้ว่าให้เปลี่ยนค่าเป็นค่าก่อนหน้าหากคุณไม่ต้องการเก็บค่าไว้ตลอดไป
Ricardo Martins

ซึ่งหมายความว่าผู้ใช้ของฉันบางคนจะมีประสบการณ์ช้ามากขึ้นใช่มั้ย
Arnold Roa

9

เมื่อคุณสร้างการเชื่อมต่อสำหรับธุรกรรมคุณได้รับการล็อกก่อนที่จะทำธุรกรรม หากไม่สามารถรับการล็อคได้คุณลองใหม่เป็นระยะ หากล็อคยังไม่สามารถหาได้แสดงว่าเกิดข้อผิดพลาดในการล็อคเกินเวลารอ สาเหตุที่คุณจะไม่สามารถรับการล็อคได้คือคุณไม่ได้ปิดการเชื่อมต่อ ดังนั้นเมื่อคุณพยายามล็อคครั้งที่สองคุณจะไม่สามารถรับล็อคเนื่องจากการเชื่อมต่อก่อนหน้าของคุณยังคงไม่ได้รับการล็อคและถือล็อค

วิธีแก้ปัญหา: ปิดการเชื่อมต่อหรือsetAutoCommit(true)(ตามการออกแบบของคุณ) เพื่อปลดล็อค


7

รีสตาร์ท MySQL มันทำงานได้ดี

แต่ระวังว่าถ้าแบบสอบถามดังกล่าวติดอยู่มีปัญหาบางอย่าง:

  • ในข้อความค้นหาของคุณ (อักขระถูกวางผิด, ผลิตภัณฑ์คาร์ทีเซียน, ... )
  • บันทึกจำนวนมากที่จะแก้ไข
  • การรวมหรือการทดสอบที่ซับซ้อน (MD5, สตริงย่อยLIKE %...%ฯลฯ )
  • ปัญหาโครงสร้างข้อมูล
  • foreign key model (การล็อคโซ่ / ลูป)
  • ข้อมูลที่ผิดพลาด

@syedrakib กล่าวว่ามันใช้งานได้ แต่นี่ไม่ใช่ทางออกที่ยาวนานสำหรับการผลิต

ระวัง: การรีสตาร์ทอาจส่งผลต่อข้อมูลของคุณด้วยสถานะที่ไม่สอดคล้องกัน

นอกจากนี้คุณสามารถตรวจสอบว่า MySQL จัดการการสืบค้นของคุณด้วยคำสำคัญอธิบายและดูว่ามีสิ่งใดบ้างที่เป็นไปได้เพื่อเร่งความเร็วการสืบค้น (ดัชนีการทดสอบที่ซับซ้อน ... )


ขอบคุณ. คุณไม่ได้แก้ปัญหาของฉันโดยตรง แต่ฉันต้องทนทุกข์ทรมานจากการล็อคโต๊ะและมันก็แย่มาก นั่นเป็นโพสต์เดียวกับอินเทอร์เน็ตทั้งหมดซึ่งทำให้ฉันมีความคิดที่จะตรวจสอบกุญแจต่างประเทศ ดังนั้นฉันจึงพบว่ากุญแจของคีย์หลักคือ 11 และกุญแจต่างประเทศ 10 ฉันไม่รู้ว่าจะเกิดอะไรขึ้นและทำไมทุกอย่างทำงานก่อน
EscapeNetscape

@EscapeNetscape คุณกำลังต้อนรับฉันดีใจที่นี้คำตอบของเล็ก ๆ น้อย ๆ ที่ช่วยให้คุณ :)
Benj

3

ไปที่กระบวนการใน mysql

ดังนั้นสามารถดูได้ว่ามีงานยังทำงานอยู่

ฆ่ากระบวนการเฉพาะหรือรอจนกว่ากระบวนการจะเสร็จสมบูรณ์


7
มันแก้ปัญหาได้ แต่นี่ไม่ใช่วิธีแก้ปัญหาสำหรับเซิร์ฟเวอร์ที่ใช้งานจริง ...... เราจะจัดการการหยุดชะงักได้อย่างไร หรือเราจะหลีกเลี่ยงการหยุดชะงักนี้ได้อย่างไร
Rakib

1
มันเกิดขึ้นอย่างนั้นแม้ว่าจะมีรูปแบบที่สมบูรณ์และหลบหนีการสืบค้น mysql ได้อย่างสมบูรณ์แบบซึ่งไม่ได้เขียนโดยนักพัฒนา แต่โดยส่วนต่อประสานที่ใช้งานบันทึกของกรอบการทำงาน ดังนั้นฉันไม่ได้เขียนแบบสอบถาม mysql ที่เหมาะสมเป็นปัจจัยที่นี่
Rakib

1

ฉันพบปัญหาเดียวกันกับ "การอัปเดต" - สถานะ โซลูชันของฉันคือการเรียกใช้การดำเนินการที่มีอยู่ใน phpMyAdmin สำหรับตาราง ฉันปรับให้เหมาะสมล้างและจัดระเบียบตาราง (ไม่อยู่ในลำดับนั้น) ไม่จำเป็นต้องวางตารางและกู้คืนจากการสำรองข้อมูลสำหรับฉัน :)


1
มันอาจแก้ปัญหาได้ แต่ต้องทำเช่นนี้ทุกครั้งที่มีข้อผิดพลาดเกิดขึ้นไม่สามารถแก้ปัญหาสำหรับเซิร์ฟเวอร์ที่ใช้งานจริง ...... เราจะจัดการการหยุดชะงักได้อย่างไร หรือเราจะหลีกเลี่ยงการหยุดชะงักนี้ได้อย่างไร
Rakib

1

ฉันมีปัญหาเดียวกัน ฉันคิดว่ามันเป็นปัญหาการหยุดชะงักของ SQL คุณสามารถบังคับปิดกระบวนการ SQL จากตัวจัดการงานได้ หากไม่สามารถแก้ไขได้ให้รีสตาร์ทคอมพิวเตอร์ คุณไม่จำเป็นต้องวางตารางและโหลดข้อมูลอีกครั้ง


มันแก้ปัญหาได้ แต่นี่ไม่ใช่วิธีแก้ปัญหาสำหรับเซิร์ฟเวอร์ที่ใช้งานจริง ...... เราจะจัดการการหยุดชะงักได้อย่างไร หรือเราจะหลีกเลี่ยงการหยุดชะงักนี้ได้อย่างไร
Rakib

รีสตาร์ท Apache และบริการ (หรืออย่างน้อย MySQL) ไม่จำเป็นต้องรีบูต
Amjo

1

ฉันมีปัญหานี้เมื่อพยายามลบกลุ่มระเบียนบางรายการ (ใช้ MS Access 2007 ที่มีการเชื่อมต่อ ODBC กับ MySQL บนเว็บเซิร์ฟเวอร์) โดยทั่วไปฉันจะลบบางระเบียนจาก MySQL จากนั้นแทนที่ด้วยระเบียนที่ปรับปรุงแล้ว (เรียงซ้อนลบระเบียนที่เกี่ยวข้องหลายรายการซึ่งจะเพิ่มความคล่องตัวในการลบระเบียนที่เกี่ยวข้องทั้งหมดสำหรับการลบระเบียนเดียว)

ฉันพยายามเรียกใช้การดำเนินการที่มีอยู่ใน phpMyAdmin สำหรับตาราง (การเพิ่มประสิทธิภาพการล้างข้อมูล ฯลฯ ) แต่ฉันได้รับการอนุญาตต้องใช้ข้อผิดพลาด RELOAD เมื่อฉันพยายามล้างข้อมูล เนื่องจากฐานข้อมูลของฉันอยู่บนเว็บเซิร์ฟเวอร์ฉันจึงไม่สามารถรีสตาร์ทฐานข้อมูลได้ การกู้คืนจากข้อมูลสำรองไม่ใช่ตัวเลือก

ฉันพยายามเรียกใช้ลบคิวรีสำหรับกลุ่มระเบียนนี้ในการเข้าถึง mySQL ของ cPanel บนเว็บ มีข้อความแสดงข้อผิดพลาดเดียวกัน

โซลูชันของฉัน: ฉันใช้ MySQL Query Browser ฟรีของ Sun (ที่ฉันติดตั้งไว้ก่อนหน้านี้ในคอมพิวเตอร์ของฉัน) และเรียกใช้คิวรีการลบที่นั่น มันทำงานได้ทันทีแก้ไขปัญหา ฉันสามารถใช้ฟังก์ชันสคริปต์อีกครั้งโดยใช้การเชื่อมต่อ ODBC เพื่อเข้าถึง MySQL


-2

ซ่อมมัน.

ตรวจสอบให้แน่ใจว่าคุณไม่มีการแทรกชนิดข้อมูลที่ไม่ตรงกันในแบบสอบถาม ฉันมีปัญหาที่ฉันพยายาม "ผู้ใช้ข้อมูลตัวแทนเบราว์เซอร์ของผู้ใช้" ในVARCHAR(255)และมีปัญหากับล็อคนี้ แต่เมื่อฉันเปลี่ยนมันเพื่อTEXT(255)แก้ไขมัน

ดังนั้นส่วนใหญ่แล้วมันเป็นประเภทข้อมูลที่ไม่ตรงกัน


-151

ฉันแก้ไขปัญหาโดยการวางตารางและกู้คืนจากการสำรองข้อมูล


20
อนึ่งคำตอบนี้ได้รับรางวัลเกียรติยศจากการเป็นคำตอบ "ยอมรับ" ต่ำสุดตลอดกาลของ SO! 🏆
ashleedawg

1
นี่เป็นคำตอบที่ได้คะแนนต่ำสุดโดยทั่วไปเช่นกัน
Bob Kerman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.