Essas duas consultas resultarão em um impasse se executadas em sequência?

12

Essa é quase certamente a causa da minha outra pergunta , mas achei que valia a pena separar as duas, pois tenho uma hipótese baseada no registro a seguir que adoraria falsificar ou verificar.

Minha hipótese é que o outro impasse seja realmente o resultado das seguintes consultas, com a consulta original oculta com base no meu entendimento de que o status innodb mostra apenas as transações mais recentes (isso está correto?).

Com base no log, verifiquei nosso código e encontrei as duas consultas a seguir executadas em sequência:

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

Onde db.Execute está basicamente executando um ExecuteNonQuery em um objeto System.Data DbCommand .

Então, essa sequência de consultas resultará em um impasse? Minha hipótese é que as duas ordens de campo diferentes nas duas consultas causam o problema? Posso agrupar as duas consultas em uma transação para resolver o conflito?

------------------------
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;;
RedBlueThing
fonte

Respostas:

7

Mesmo que as instruções sejam executadas em sequência, se elas existirem na mesma transação, você deve emitir algum tipo de ponto de verificação entre as consultas ou ajustar o nível de isolamento da transação antes de iniciar a transação.

Existem quatro valores para tx_isolation:

Você pode definir o isolamento da transação de três (3) maneiras:

Escreva isso em /etc/my.cnf e reinicie o mysql

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

ou você pode configurá-lo na própria conexão com o banco de dados antes de iniciar qualquer nova transação:

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

ou desabilite a confirmação automática usando protocolos .NET (Isenção de responsabilidade: não sou desenvolvedor .NET)

Embora eu esteja inclinado para READ-UNCOMMITTED para permitir "leituras sujas", você deve experimentar outros níveis de isolamento de transação em algum momento para ver qual deles tem o efeito desejado.

De uma chance !!!

RolandoMySQLDBA
fonte
4

Acontece que essas duas consultas eram pelo menos parte do problema que estávamos tendo. Modificamos essas duas consultas de:

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

para:

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

Portanto, não estamos mais atualizando o registro inteiro (por várias chaves) e os campos na mesma ordem. Desde que fizemos a alteração, nossos impasses desapareceram.

RedBlueThing
fonte