【问题标题】:InnoDB locking a different index while using a where clause on a foreign keyInnoDB 在外键上使用 where 子句时锁定不同的索引
【发布时间】:2018-06-19 15:35:27
【问题描述】:

我正在两个不同的事务中尝试这些查询:

START TRANSACTION;
DELETE FROM `StopHistory` WHERE `deviceId` = 34;

START TRANSACTION;
SELECT id FROM `StopHistory` WHERE deviceId = 33 AND endAt > '2018-06-18 17:01:32.473';

第二个查询等待,因为第一个查询在 endAt 字段上创建一个锁。

MySQL [(none)]> select * from INFORMATION_SCHEMA.INNODB_LOCKS;
+-----------------------+-------------+-----------+-----------+--------------------------+------------+------------+-----------+----------+--------------------------+
| lock_id               | lock_trx_id | lock_mode | lock_type | lock_table               | lock_index | lock_space | lock_page | lock_rec | lock_data                |
+-----------------------+-------------+-----------+-----------+--------------------------+------------+------------+-----------+----------+--------------------------+
| 104222007:699:1035:16 | 104222007   | S         | RECORD    | `db`.`StopHistory`       | endAt      |        641 |      1035 |       16 | 0x99A026D21307DA, 115347 |
| 104221958:699:1035:16 | 104221958   | X         | RECORD    | `db`.`StopHistory`       | endAt      |        641 |      1035 |       16 | 0x99A026D21307DA, 115347 |
+-----------------------+-------------+-----------+-----------+--------------------------+------------+------------+-----------+----------+--------------------------+

    ---TRANSACTION 104231466, ACTIVE 3 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 376, 3 row lock(s)
MySQL thread id 59556, OS thread handle 0x2b1375f03700, query id 20584248 172.31.2.181 db Sending data
SELECT id FROM `StopHistory` WHERE deviceId = 33 AND endAt > '2018-06-18 17:01:32.473'
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 641 page no 1035 n bits 16 index `endAt` of table `db`.`StopHistory` trx id 104231466 lock mode S waiting
Record lock, heap no 16 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len=7; bufptr=0x2b134db1c16c; hex= 99a026d21307da; asc   &    ;;
 1: len=4; bufptr=0x2b134db1c173; hex= 8001c293; asc     ;;

------------------
---TRANSACTION 104231429, ACTIVE 11 sec
44 lock struct(s), heap size 376, 3103 row lock(s), undo log entries 1549
MySQL thread id 59555, OS thread handle 0x2b1375f03700, query id 20584210 172.31.2.181 db delayed send ok done

StopHistory 表在 deviceId 上有一个外键,在 endAt 上有一个索引

CREATE TABLE `StopHistory` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `endAt` datetime(3) DEFAULT NULL,
  `deviceId` int(11) DEFAULT NULL,
  `beginAt` datetime(3) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_StopHystory_2_idx` (`deviceId`),
  KEY `beginAt` (`beginAt`),
  KEY `endAt` (`endAt`),
  KEY `device_beginAt` (`deviceId`,`beginAt`),
  CONSTRAINT `fk_StopHystory_2` FOREIGN KEY (`deviceId`) REFERENCES `Devices` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=115351 DEFAULT CHARSET=utf8;

解释的输出:

MySQL [db]> explain DELETE FROM `StopHistory` WHERE `deviceId` = 34 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: StopHistory
         type: range
possible_keys: PRIMARY,fk_StopHystory_1_idx,fk_StopHystory_2_idx,fk_StopHistory_1_idx,beginAt,endAt,device_beginAt
          key: fk_StopHystory_2_idx
      key_len: 5
          ref: NULL
         rows: 1548
        Extra: Using where

为什么 endAt 字段被锁定?

【问题讨论】:

  • 我猜删除并没有影响外键关系更改,因此 InnoDB 引擎没有锁定外键索引记录,以将所有外键关系记录的性能和可访问性保持在其他查询的最大值...因此,Devices 表中的 DELETE 应该锁定外键索引记录

标签: mysql transactions locking mariadb innodb


【解决方案1】:

为了帮助SELECT,并可能减少锁定的机会,请更改

KEY `fk_StopHystory_2_idx` (`deviceId`),

KEY(deviceId, endAt)

另外,请注意 34 紧跟在 33 之后。因此,删除所有 34 就是触及 33 之后的“间隙”。这可能是锁争用的一个不可避免的原因。

还请注意,DELETE 需要从 3 个 BTree 中删除项目——主要的 BTree,加上以 deviceId 开头的两个索引。想必后两者都会经过“Change Buffer”,不会太挑剔。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-12
    • 2011-03-25
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 2014-04-16
    • 1970-01-01
    • 2010-10-09
    相关资源
    最近更新 更多