Bedeutung von "Sperren rec, aber keine Lücke warten" im Deadlock-Bericht

12
  1. Über die Bedeutung von locks rec but not gap waitingin TRANSACTION (1), welche ist richtig?

    • Bereits gewährte Lückensperre, Warten auf Clustered Index X-Sperre?
    • Bereits gewährte Clustered Index X-Sperre, wartet auf Lückenlücke?
  2. Es gibt 31 Zeilen in Transaktion (1). Was bedeuten diese Zeilen? Stellt dies eine Lückenverriegelung dar?

     0: len 4; hex 800c20d6; asc     ;;
     ....
     29: SQL NULL;
     30: SQL NULL;

NEUESTER ERKANNTER DEADLOCK-Bericht

    LATEST DETECTED DEADLOCK
    ------------------------
    2015-09-25 15:27:24 1b8084000


    *** (1) TRANSACTION:
    TRANSACTION 5226928, ACTIVE 0 sec fetching rows
    mysql tables in use 1, locked 1
    LOCK WAIT 31 lock struct(s), heap size 6544, 548 row lock(s)
    MySQL thread id 71, OS thread handle 0x1b45be000, query id 4085356 localhost root Creating sort index
    SELECT  `rpush_notifications`.* FROM `rpush_notifications`  WHERE (processing = 0 AND delivered = 0 AND failed = 0 AND (deliver_after IS NULL OR deliver_after < '2015-09-25 07:27:24'))  ORDER BY created_at ASC LIMIT 100 FOR UPDATE


    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 10287 page no 10901 n bits 152 index `PRIMARY` of table `ct_development`.`rpush_notifications` trx id 5226928 lock_mode X locks rec but not gap waiting
    Record lock, heap no 78 PHYSICAL RECORD: n_fields 31; compact format; info bits 0
     0: len 4; hex 800c20d6; asc     ;;
     1: len 6; hex 0000004fc1aa; asc    O  ;;
     2: len 7; hex 4c0000027b07fe; asc L   {  ;;
     3: len 30; hex 52707573683a3a436c69656e743a3a4163746976655265636f72643a3a41; asc Rpush::Client::ActiveRecord::A; (total 47 bytes);
     4: SQL NULL;
     5: len 30; hex 373838653836643365666465626262626639633464363261626433366132; asc 788e86d3efdebbbbf9c4d62abd36a2; (total 64 bytes);
     6: len 7; hex 64656661756c74; asc default;;
     7: len 7; hex 6869206d6f6d21; asc hi mom!;;
     8: len 13; hex 7b22666f6f223a22626172227d; asc {"foo":"bar"};;
     9: len 4; hex 80015180; asc   Q ;;
     10: len 1; hex 80; asc  ;;
     11: SQL NULL;
     12: len 1; hex 81; asc  ;;
     13: len 5; hex 99973276d8; asc   2v ;;
     14: SQL NULL;
     15: len 0; hex ; asc ;;
     16: SQL NULL;
     17: len 5; hex 99973276d6; asc   2v ;;
     18: len 5; hex 99973276d6; asc   2v ;;
     19: len 1; hex 80; asc  ;;
     20: SQL NULL;
     21: len 1; hex 80; asc  ;;
     22: SQL NULL;
     23: len 4; hex 80000002; asc     ;;
     24: len 4; hex 80000000; asc     ;;
     25: SQL NULL;
     26: SQL NULL;
     27: len 1; hex 80; asc  ;;
     28: SQL NULL;
     29: SQL NULL;
     30: SQL NULL;

    *** (2) TRANSACTION:

    TRANSACTION 5226922, ACTIVE 0 sec updating or deleting, thread declared inside InnoDB 0
    mysql tables in use 1, locked 1
    3 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 1
    MySQL thread id 1446, OS thread handle 0x1b8084000, query id 4085345 localhost root updating
    UPDATE `rpush_notifications` SET processing = 0, delivered = 0, delivered_at = NULL, failed = 1, failed_at = '2015-09-25 07:27:24', error_code = NULL, error_description = '' WHERE `rpush_notifications`.`id` IN (794838, 794839)


    *** (2) HOLDS THE LOCK(S):
    RECORD LOCKS space id 10287 page no 10901 n bits 152 index `PRIMARY` of table `ct_development`.`rpush_notifications` trx id 5226922 lock_mode X locks rec but not gap
    Record lock, heap no 78 PHYSICAL RECORD: n_fields 31; compact format; info bits 0
     0: len 4; hex 800c20d6; asc     ;;
     1: len 6; hex 0000004fc1aa; asc    O  ;;
     2: len 7; hex 4c0000027b07fe; asc L   {  ;;
     3: len 30; hex 52707573683a3a436c69656e743a3a4163746976655265636f72643a3a41; asc Rpush::Client::ActiveRecord::A; (total 47 bytes);
     4: SQL NULL;
     5: len 30; hex 373838653836643365666465626262626639633464363261626433366132; asc 788e86d3efdebbbbf9c4d62abd36a2; (total 64 bytes);
     6: len 7; hex 64656661756c74; asc default;;
     7: len 7; hex 6869206d6f6d21; asc hi mom!;;
     8: len 13; hex 7b22666f6f223a22626172227d; asc {"foo":"bar"};;
     9: len 4; hex 80015180; asc   Q ;;
     10: len 1; hex 80; asc  ;;
     11: SQL NULL;
     12: len 1; hex 81; asc  ;;
     13: len 5; hex 99973276d8; asc   2v ;;
     14: SQL NULL;
     15: len 0; hex ; asc ;;
     16: SQL NULL;
     17: len 5; hex 99973276d6; asc   2v ;;
     18: len 5; hex 99973276d6; asc   2v ;;
     19: len 1; hex 80; asc  ;;
     20: SQL NULL;
     21: len 1; hex 80; asc  ;;
     22: SQL NULL;
     23: len 4; hex 80000002; asc     ;;
     24: len 4; hex 80000000; asc     ;;
     25: SQL NULL;
     26: SQL NULL;
     27: len 1; hex 80; asc  ;;
     28: SQL NULL;
     29: SQL NULL;
     30: SQL NULL;

    *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 10287 page no 7992 n bits 1480 index `index_rpush_notifications_multi` of table `ct_development`.`rpush_notifications` trx id 5226922 lock_mode X locks rec but not gap waiting
    Record lock, heap no 1279 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
     0: len 1; hex 80; asc  ;;
     1: len 1; hex 80; asc  ;;
     2: len 4; hex 800c20d6; asc     ;;

    *** WE ROLL BACK TRANSACTION (2)

Tabellenschema

CREATE TABLE `rpush_notifications` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(255) NOT NULL,
  `badge` int(11) DEFAULT NULL,
  `device_token` varchar(64) DEFAULT NULL,
  `sound` varchar(255) DEFAULT 'default',
  `alert` varchar(255) DEFAULT NULL,
  `data` text,
  `expiry` int(11) DEFAULT '86400',
  `delivered` tinyint(1) NOT NULL DEFAULT '0',
  `delivered_at` datetime DEFAULT NULL,
  `failed` tinyint(1) NOT NULL DEFAULT '0',
  `failed_at` datetime DEFAULT NULL,
  `error_code` int(11) DEFAULT NULL,
  `error_description` text,
  `deliver_after` datetime DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `alert_is_json` tinyint(1) DEFAULT '0',
  `collapse_key` varchar(255) DEFAULT NULL,
  `delay_while_idle` tinyint(1) NOT NULL DEFAULT '0',
  `registration_ids` mediumtext,
  `app_id` int(11) NOT NULL,
  `retries` int(11) DEFAULT '0',
  `uri` varchar(255) DEFAULT NULL,
  `fail_after` datetime DEFAULT NULL,
  `processing` tinyint(1) NOT NULL DEFAULT '0',
  `priority` int(11) DEFAULT NULL,
  `url_args` text,
  `category` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_rapns_notifications_multi` (`app_id`,`delivered`,`failed`,`deliver_after`),
  KEY `index_rpush_notifications_multi` (`delivered`,`failed`)
) ENGINE=InnoDB AUTO_INCREMENT=337371 DEFAULT CHARSET=utf8;
Ryan Lv
quelle

Antworten:

20

Frage 1: InnoDB versucht, eine exklusive Sperre für die Zeile zu erhalten (es ist tatsächlich eine Sperre für den Clustered-Index-Datensatz, die PK), aber nicht für die umgebende Lücke (eine Lücken-Sperre). Weitere Informationen zu Datensatz- und Lückensperren finden Sie hier: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-record-locks

Die exklusive Sperranforderung stammt aus der Klausel "for update", die der SELECT-Anweisung hinzugefügt wurde. Beachten Sie, dass bei Verwendung der Standardeinstellung für wiederholbares Lesen (wählen Sie @@ session.tx_isolation), die die Standardeinstellung ist, die exklusive Sperre für jede für SELECT untersuchte Zeile gesetzt wird , nicht nur für die zurückgegebenen (die übereinstimmenden) alle Prädikate in der WHERE-Klausel). So können Sie möglicherweise die Anzahl der untersuchten Zeilen und damit die gehaltenen Sperren reduzieren, wodurch die Wahrscheinlichkeit von Konflikten erheblich verringert wird, indem Sie einen zusammengesetzten Index für Folgendes verwenden: Verarbeitung, Zustellung, Fehlgeschlagen, Zustellung_nachher

Ich weiß nicht, wie hoch die Kardinalität (Anzahl der eindeutigen Werte) für diese Spalten ist, aber Sie sollten sie im Allgemeinen im zusammengesetzten Index von der höchsten zur niedrigsten Kardinalität auflisten.

 

Frage 2: 31 ist die Anzahl der Felder im Indexdatensatz (oder logischerweise in der Zeile), auf die versucht wird, eine exklusive Sperre zu erhalten. InnoDB verwendet eine Cluster-PK, sodass die Datensätze im Clustered-Index (PK) die Felder für jede benutzerdefinierte Spalte enthalten - 29 Felder bei Ihrer Tabelle push_notifications: id ... category - und es gibt immer zwei zusätzliche Interne Felder für jede InnoDB-Tabelle: ein 6-Byte-Transaktions-ID-Feld und ein 7-Byte-Roll-Zeigerfeld (diese werden für MVCC verwendet). Die 31 aufgelisteten Elemente sind also die Felder im Indexdatensatz (oder logischerweise in der Zeile), auf die wir warten, bis die Sperre aktiviert ist.

 

Nur zu Ihrer Information : Sie können weitere Aufschlüsselungen von InnoDB-Sperren mithilfe neuer Information_Schema-Tabellen in 5.6+ erhalten: https://dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-transactions.html

Es gibt auch einige großartige Berichte im neuen SYS-Schema, das im Server in MySQL 5.7+ enthalten ist (hat aber noch nicht ganz in das Online-Handbuch aufgenommen): https://github.com/MarkLeith/mysql-sys # innodb_lock_waits - xinnodb_lock_waits

Sie können das neueste SYS-Schema in MySQL 5.6 manuell installieren, wenn es von Interesse ist: https://github.com/MarkLeith/mysql-sys/blob/master/sys_56.sql

Für weitere Informationen: http://www.slideshare.net/Leithal/performance-schema-and-sys-schema-in-mysql-57

 

Ich hoffe das hilft!

Matt Lord
quelle