1

Die nächste Ausgabe mit dieser Konfiguration aufwirft:MySQL: in einer einzigen Tabelle UPDATE Deadlock ... WHERE

  • MySQL 5.7.10
  • Frühling 4.0.5
  • Spring Batch 3.0.1
  • Frühling ThreadPoolTaskExecutor zwischen 10 und 20 Fäden

Das Problem ist ein Deadlock, wenn einige Threads versuchen, ein Update zu tun ... WHERE in einer einzigen Tabelle.

Der Tisch ist:

CREATE TABLE IF NOT EXISTS `invoice_events` (
    `INTERNAL_ID` bigint(20) NOT NULL, 
    `FECHA_FAC` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `PERIOD_TYPE` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `PRODUCT_ID` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `RATE_ID` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `INVOICE_INTERNAL_ID` bigint(20) unsigned DEFAULT NULL, 
    `COUNTRY_CODE` varchar(4) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `SOURCE_MSISDN` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `TARGET_MSISDN` varchar(100) CHARACTER SET utf8 DEFAULT NULL, 
    `CATEGORY` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `SERVICE` varchar(50) COLLATE utf8_spanish_ci DEFAULT NULL, 
    `USAGE_TYPE` varchar(50) CHARACTER SET utf8 DEFAULT NULL, 
    `BT_COST` double(22,6) DEFAULT NULL, 
    PRIMARY KEY (`INTERNAL_ID`,`FECHA_FAC`), 
    KEY `IDX_INV_INT_ID` (`INVOICE_INTERNAL_ID`), 
    KEY `IDX_MSISDN` (`SOURCE_MSISDN`), 
    KEY `IDX_FECHA_FAC` (`FECHA_FAC`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci 
PARTITION BY RANGE(TO_DAYS(FECHA_FAC)) (
    PARTITION p201511 VALUES LESS THAN (TO_DAYS('2015-12-01')), 
    PARTITION p201512 VALUES LESS THAN (TO_DAYS('2016-01-01')), 
    PARTITION p201601 VALUES LESS THAN (TO_DAYS('2016-02-01')), 
    PARTITION p201602 VALUES LESS THAN (TO_DAYS('2016-03-01')), 
    PARTITION p201603 VALUES LESS THAN (TO_DAYS('2016-04-01')), 
    PARTITION p201604 VALUES LESS THAN (TO_DAYS('2016-05-01')), 
    PARTITION p201605 VALUES LESS THAN (TO_DAYS('2016-06-01')), 
    PARTITION p201606 VALUES LESS THAN (TO_DAYS('2016-07-01')), 
    PARTITION p201607 VALUES LESS THAN (TO_DAYS('2016-08-01')), 
    PARTITION p201608 VALUES LESS THAN (TO_DAYS('2016-09-01')), 
    PARTITION p201609 VALUES LESS THAN (TO_DAYS('2016-10-01')), 
    PARTITION p201610 VALUES LESS THAN (TO_DAYS('2016-11-01')), 
    PARTITION p201611 VALUES LESS THAN (TO_DAYS('2016-12-01')), 
    PARTITION future VALUES LESS THAN MAXVALUE 
); 

Die UPDATE-Anweisung ist:

update invoice_events 
set invoice_internal_id = 978202 
where fecha_fac between '2016-02-01 00:00:00' and '2016-05-31 23:59:59.999' 
and source_msisdn = '239642983472' 
and invoice_internal_id is null 
and country_code = 'ES'; 

Die MySQL EXPLAIN ist für diese Aussage ist: enter image description here

Die SHOW STATUS MOTOR des Problems ist:

2016-06-03 11:08:23 0x7f8bcc1aa700 
*** (1) TRANSACTION: 
TRANSACTION 7031093, ACTIVE 0 sec fetching rows 
mysql tables in use 1, locked 1 
LOCK WAIT 406 lock struct(s), heap size 41168, 2884 row lock(s), undo log entries 375 
MySQL thread id 4726, OS thread handle 140238271616768, query id 10226209 172.30.6.9 BDUSER updating 
update invoice_events set invoice_internal_id = 978173 where fecha_fac between '2016-02-01 00:00:00' and '2016-05-31 23:59:59.999' and source_msisdn in ('239642983345') and invoice_internal_id is null and country_code = 'ES' 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 12252 page no 54015 n bits 512 index IDX_MSISDN of table `my_schema`.`invoice_events` /* Partition `p201603` */ trx id 7031093 lock_mode X waiting 
Record lock, heap no 101 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 16; hex 33303835303732313033323532303132; asc 3085072103252012;; 
1: len 8; hex 80000000005d2fa3; asc  ]/ ;; 
2: len 5; hex 9998fe0000; asc  ;; 

*** (2) TRANSACTION: 
TRANSACTION 7031094, ACTIVE 0 sec starting index read, thread declared inside InnoDB 4999 
mysql tables in use 1, locked 1 
424 lock struct(s), heap size 41168, 3945 row lock(s), undo log entries 628 
MySQL thread id 4731, OS thread handle 140238401480448, query id 10226408 172.30.6.9 BDUSER updating 
update invoice_events set invoice_internal_id = 978202 where fecha_fac between '2016-02-01 00:00:00' and '2016-05-31 23:59:59.999' and source_msisdn in ('239642983472') and invoice_internal_id is null and country_code = 'ES' 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 12252 page no 54015 n bits 512 index IDX_MSISDN of table `my_schema`.`invoice_events` /* Partition `p201603` */ trx id 7031094 lock_mode X 
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 
0: len 8; hex 73757072656d756d; asc supremum;; 

Von innodb Datenbankvariablen, bemerke ich innodb_thread_concurrency Wert 32.

Die ausgewählten Partitionen enthält 21.853.907 Zeilen ist.

Ich habe versucht, eine einfache UPDATE-Anweisung zu machen. Ich filtere nur mit fecha_fac, um auf die erforderlichen Partitionen zuzugreifen, und filtere dann mit indizierten Feldern.

Also, meine erste und wichtigste Frage ist: Wie kann ich diese Transaktionssperre beheben? Irgendwelche Tipps, Trinkgeld, ...?

Alle anderen wichtigen Fragen sind:

  • Vom Ausgang ERKLÄREN: könnte Typ (Bereich) besser sein, sogar in einer einzigen Tabelle Update? Oder ist es der beste Typ für ein Single-Table-Update?
  • Von der EXPLAIN-Ausgabe: Ist es richtig, dass der letzte Schlüssel IDX_INV_INT_ID anstelle von IDX_MSISDN war? IDX_INV_INT_ID indiziert eine Nullspalte.
  • Wird der Parameter innodb_thread_concurrency auf 0 gesetzt (unendliche Nebenläufigkeit)?
  • Gibt es irgendwelche Daten in der SHOW STATUS-Ausgabe, die mir helfen könnten und ich nicht bemerkt habe?

Zusätzlich zu meinen Fragen wird jede Hilfe oder Beratung sehr geschätzt.

Vielen Dank im Voraus.

+0

Ihre vorhandenen Indizes scheinen diese Aktualisierungsabfrage nicht wirklich zu unterstützen, daher kann es eine Weile dauern, bis MySQL die Aktualisierung durchführt und möglicherweise eine große Anzahl von Index- und tatsächlichen Datensätzen scannen muss, die den Deadlock verursachen. Ich denke, Sie sollten versuchen, einen besser deckenden Index auf der Grundlage der Wo-Kriterien zu erstellen. – Shadow

+0

@Shadow, vielen Dank. Dein Vorschlag hilft mir. –

Antwort

0

Wie @Shadow vorgeschlagen, habe ich Indizes überprüft, und nur IDX_MSISDN bleibt.

Andere gute Praktiken für die DB-Design und Deadlock zu vermeiden, habe ich gemacht sind:

  • Spalten neu sortieren. Mögliche NULL und/oder nicht indexierte Spalten wurden an das Ende verschoben.
  • Spaltenspalte Datentyp und Größe mit PROCEDURE ANALYZE() anpassen. Zum Beispiel wurde SOURCE_MSISDN reduziert, also auch key_len reduziert.
  • Synchronisierte Transaktionen. Es wird nur eine Transaktion pro Spring Batch-Element ausgeführt. In meinem Design ist der Durchsatz um 5-10% gesunken, und es ist überschaubar.

Ich hoffe, es hilft.

Verwandte Themen