1

下一個問題與此配置提出:MySQL的:死鎖在一個表中UPDATE ... WHERE

  • 的MySQL 5.7.10
  • 春4.0.5
  • Spring Batch的3.0.1
  • 10線程和20線程之間的Thread ThreadPoolTask​​Executor

當某些線程試圖在單個表中執行UPDATE ... WHERE時,問題就是死鎖。

表是:

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

UPDATE語句是:

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

的MySQL的解釋這種說法是: enter image description here

問題的SHOW狀態引擎是:

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

從innodb的數據庫的變量,我注意到innodb_thread_concurrency參數值爲32

選定分區包含21853907行。

我試圖做一個簡單的UPDATE語句。我使用fecha_fac過濾僅用於訪問所需的分區,然後使用索引字段進行過濾。

所以,我的第一個和主要問題是:我該如何解決這個事務鎖?任何建議,小費,......?

任何其他重要的問題是:

  • 從EXPLAIN輸出:可以輸入(範圍)會更好,即使在單個表更新?或者它是單表更新的最佳類型?
  • 從EXPLAIN輸出:最後一個鍵是IDX_INV_INT_ID而不是IDX_MSISDN是正確的嗎? IDX_INV_INT_ID索引一個空列。
  • 它有助於將innodb_thread_concurrency參數設置爲0(無限併發)嗎?
  • 顯示狀態輸出中是否有任何數據,這可以幫助我,我沒有注意到?

除了我的問題,任何幫助或建議,非常感謝。

在此先感謝。

+0

您的現有索引似乎無法幫助此更新查詢,因此MySQL可能需要一段時間才能執行更新,並且可能必須掃描導致死鎖的各種索引和實際數據記錄。我認爲你應該嘗試根據哪些標準創建更多覆蓋指數。 – Shadow

+0

@Shadow,非常感謝。你的建議可以幫助我。 –

回答

0

正如@Shadow建議的那樣,我檢查了索引,並且只保留了IDX_MSISDN。對於DB設計和避免死鎖我已經

其他好的做法是:

  • 重新排序列。可能的NULL和/或未索引的列已被移動到最後。
  • 使用PROCEDURE ANALYZE()適合列數據類型和大小。例如,SOURCE_MSISDN已經減少,那麼key_len也會減少。
  • 同步交易。每個Spring Batch項目只執行一個事務。在我的設計中,吞吐量下降了大約5-10%,並且可以管理。

希望它有幫助。