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


12

นี่เป็นสาเหตุของคำถามอื่น ๆ ของฉันแต่ฉันคิดว่ามันคุ้มค่าที่จะแยกทั้งสองออกจากกันเนื่องจากฉันมีสมมติฐานตามบันทึกต่อไปนี้ที่ฉันชอบที่จะปลอมแปลงหรือตรวจสอบ

สมมติฐานของฉันคือว่าการหยุดชะงักอื่น ๆเป็นผลมาจากการสอบถามต่อไปนี้โดยมีการซ่อนแบบสอบถามดั้งเดิมที่อยู่บนพื้นฐานของความเข้าใจของฉันสถานะ Innodb แสดงเฉพาะธุรกรรมล่าสุด (ถูกต้องหรือไม่)

จากบันทึกฉันได้ตรวจสอบรหัสของเราและพบว่ามีการค้นหาสองรายการต่อไปนี้ตามลำดับ:

db.Execute("UPDATE people SET iphone_device_id=NULL WHERE iphone_device_id=@0 AND people_id<>@1", DeviceID, m_User.people_id);
// I have hard coded this query in this snippet to simplify things
db.Execute("UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>', temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com', phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>', iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47', location_lat = <lat>, location_long = <lng>, gps_strength = 66, picture_blob_id = 1661, authority = 1, active = 1, date_created = '2011-03-20 19:18:34', last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55, battery_state = 'unplugged' WHERE people_id = 666");

โดยที่ db.Execute กำลังทำExecuteNonQueryบนวัตถุSystem.Data DbCommand

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

------------------------
LATEST DETECTED DEADLOCK
------------------------
110607 11:15:01
*** (1) TRANSACTION:
TRANSACTION 0 45674214, ACTIVE 0 sec, OS thread id 2584 starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1216, 2 row lock(s)
    MySQL thread id 109, query id 4044915 localhost 127.0.0.1 famdev Searching rows for update
    UPDATE people SET iphone_device_id=NULL WHERE iphone_device_id='iphone:<device_id_blah>' AND people_id<>666
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 0 page no 4611 n bits 152 index `PRIMARY` of table `family`.`people` trx id 0 45674214 lock_mode X locks rec but not gap waiting
    Record lock, heap no 7 PHYSICAL RECORD: n_fields 25; compact format; info bits 0
    0: len 8; hex 8000000000000941; asc        A;; 1: len 6; hex 000002b8eedf; asc       ;; 2: len 7; hex 00000002801064; asc       d;; 3: len 8; hex 80000000000004c6; asc         ;; 4: len 3; hex 446164; asc Dad;; 5: len 30; hex <data0>; asc <data1>;...(truncated); 6: SQL NULL; 7: SQL NULL; 8: len 17; hex <data2>; asc <redacted>@gmail.com;; 9: SQL NULL; 10: SQL NULL; 11: len 30; hex <data3>; asc iphone:<data4>;...(truncated); 12: len 8; hex <data5>; asc    J]  };; 13: len 8; hex <data6>; asc    J]   ;; 14: len 8; hex <data7>; asc ~t  g C@;; 15: len 8; hex <data8>; asc G  I &S ;; 16: len 2; hex 8042; asc  B;; 17: len 8; hex <data9>; asc        };; 18: len 4; hex <data10>; asc     ;; 19: len 1; hex 81; asc  ;; 20: len 8; hex <data11>; asc    JL} Z;; 21: len 8; hex <data12>; asc    J]  M;; 22: len 1; hex 80; asc  ;; 23: len 8; hex <data13>; asc        ?;; 24: len 9; hex <data14>; asc unplugged;;

    *** (2) TRANSACTION:
    TRANSACTION 0 45674209, ACTIVE 0 sec, OS thread id 3804 starting index read, thread declared inside InnoDB 500
    mysql tables in use 1, locked 1
    5 lock struct(s), heap size 1216, 2 row lock(s), undo log entries 1
    MySQL thread id 110, query id 4044916 localhost 127.0.0.1 famdev Updating
    UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>', temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com', phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>', iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47', location_lat = <lat>, location_long = <lng>, gps_strength = 66, picture_blob_id = 1661, authority = 1, active = 1, date_created = '2011-03-20 19:18:34', last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55, battery_state = 'unplugged' WHERE people_id = 666
    *** (2) HOLDS THE LOCK(S):
        RECORD LOCKS space id 0 page no 4611 n bits 152 index `PRIMARY` of table `family`.`people` trx id 0 45674209 lock mode S locks rec but not gap
        Record lock, heap no 7 PHYSICAL RECORD: n_fields 25; compact format; info bits 0
        0: len 8; hex 8000000000000941; asc        A;; 1: len 6; hex 000002b8eedf; asc       ;; 2: len 7; hex 00000002801064; asc       d;; 3: len 8; hex 80000000000004c6; asc         ;; 4: len 3; hex 446164; asc Dad;; 5: len 30; hex <data0>; asc <data1>;...(truncated); 6: SQL NULL; 7: SQL NULL; 8: len 17; hex <data2>; asc <redacted>@gmail.com;; 9: SQL NULL; 10: SQL NULL; 11: len 30; hex <data3>; asc iphone:<data4>;...(truncated); 12: len 8; hex <data5>; asc    J]  };; 13: len 8; hex <data6>; asc    J]   ;; 14: len 8; hex <data7>; asc ~t  g C@;; 15: len 8; hex <data8>; asc G  I &S ;; 16: len 2; hex 8042; asc  B;; 17: len 8; hex <data9>; asc        };; 18: len 4; hex <data10>; asc     ;; 19: len 1; hex 81; asc  ;; 20: len 8; hex <data11>; asc    JL} Z;; 21: len 8; hex <data12>; asc    J]  M;; 22: len 1; hex 80; asc  ;; 23: len 8; hex <data13>; asc        ?;; 24: len 9; hex <data14>; asc unplugged;;

        *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
        RECORD LOCKS space id 0 page no 4611 n bits 152 index `PRIMARY` of table `family`.`people` trx id 0 45674209 lock_mode X locks rec but not gap waiting
        Record lock, heap no 7 PHYSICAL RECORD: n_fields 25; compact format; info bits 0
        0: len 8; hex 8000000000000941; asc        A;; 1: len 6; hex 000002b8eedf; asc       ;; 2: len 7; hex 00000002801064; asc       d;; 3: len 8; hex 80000000000004c6; asc         ;; 4: len 3; hex 446164; asc Dad;; 5: len 30; hex <data0>; asc <data1>;...(truncated); 6: SQL NULL; 7: SQL NULL; 8: len 17; hex <data2>; asc <redacted>@gmail.com;; 9: SQL NULL; 10: SQL NULL; 11: len 30; hex <data3>; asc iphone:<data4>;...(truncated); 12: len 8; hex <data5>; asc    J]  };; 13: len 8; hex <data6>; asc    J]   ;; 14: len 8; hex <data7>; asc ~t  g C@;; 15: len 8; hex <data8>; asc G  I &S ;; 16: len 2; hex 8042; asc  B;; 17: len 8; hex <data9>; asc        };; 18: len 4; hex <data10>; asc     ;; 19: len 1; hex 81; asc  ;; 20: len 8; hex <data11>; asc    JL} Z;; 21: len 8; hex <data12>; asc    J]  M;; 22: len 1; hex 80; asc  ;; 23: len 8; hex <data13>; asc        ?;; 24: len 9; hex <data14>; asc unplugged;;

คำตอบ:


7

แม้ว่าคำสั่งจะถูกดำเนินการตามลำดับหากมีอยู่ภายในธุรกรรมเดียวกันคุณต้องออกจุดตรวจสอบบางอย่างระหว่างแบบสอบถามหรือดูระดับการแยกธุรกรรมก่อนที่จะเริ่มทำธุรกรรม

มีสี่ค่าสำหรับ tx_isolation:

คุณสามารถตั้งค่าแยกธุรกรรมสาม (3) วิธี:

เขียนสิ่งนี้ใน /etc/my.cnf และรีสตาร์ท mysql

[mysqld]
autocommit=0
transaction-isolation = READ-UNCOMMITTED

หรือคุณสามารถตั้งค่าภายในการเชื่อมต่อฐานข้อมูลก่อนที่จะเริ่มธุรกรรมใหม่:

db.Execute("SET tx_isolation = 'READ-UNCOMMITTED'");
db.Execute("SET autocommit = 0");

หรือปิดการใช้งาน autocommit โดยใช้โปรโตคอล. NET (ข้อจำกัดความรับผิดชอบ: ฉันไม่ใช่นักพัฒนา. NET)

แม้ว่าฉันจะเอนตัวไปยัง READ-UNCOMMITTED เพื่ออนุญาตให้ "อ่านสกปรก" คุณต้องทดลองกับระดับการแยกธุรกรรมอื่น ๆ ในบางจุดเพื่อดูว่ามีใครมีผลที่ต้องการ

ให้มันลอง !!!


4

ดังนั้นจึงปรากฎว่าแบบสอบถามทั้งสองนี้เป็นส่วนหนึ่งของปัญหาที่เราพบ เราได้แก้ไขข้อความค้นหาทั้งสองนี้จาก:

db.Execute("UPDATE people SET iphone_device_id=NULL WHERE iphone_device_id=@0 AND people_id<>@1", DeviceID, m_User.people_id);
db.Execute("UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>', temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com', phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>', iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47', location_lat = <lat>, location_long = <lng>, gps_strength = 66, picture_blob_id = 1661, authority = 1, active = 1, date_created = '2011-03-20 19:18:34', last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55, battery_state = 'unplugged' WHERE people_id = 666");

ถึง:

db.Execute("UPDATE people SET iphone_device_id=NULL WHERE iphone_device_id=@0 AND people_id<>@1", DeviceID, m_User.people_id);
db.Execute("UPDATE people SET iphone_device_id=@0, iphone_device_time=@1, last_login=@1 WHERE people_id=@2", DeviceID, System.DateTime.UtcNow, m_User.people_id);

ดังนั้นเราจะไม่อัปเดตทั้งระเบียน (ข้ามหลายคีย์) อีกต่อไปและเรากำลังอัปเดตฟิลด์ในลำดับเดียวกัน เนื่องจากเราทำการเปลี่ยนแปลงการหยุดชะงักของเราจึงหายไป

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