Mysql 超过插入锁等待超时 - 自动递增

Mysql insert lock wait timeout exceeded - auto increment

我的应用程序有问题导致 MySQL table 由于插入需要很长时间而被锁定,在查看在线文章后,它似乎与自动增量有关, 以下信息 -

Python 插入数据(不幸的是一次一行,因为我需要自动递增的 id 以供将来插入时参考)-

for i, flightobj in stats[ucid]['flight'].items():
            flight_fk = None
            # Insert flights
            try:
                with mysqlconnection.cursor() as cursor:
                    sql = "insert into cb_flights(ucid,takeoff_time,end_time,end_event,side,kills,type,map_fk,era_fk) values(%s,%s,%s,%s,%s,%s,%s,%s,%s);"
                    cursor.execute(sql, (
                    ucid, flightobj['start_time'], flightobj['end_time'], flightobj['end_event'], flightobj['side'],
                    flightobj['killnum'], flightobj['type'], map_fk, era_fk))
                    mysqlconnection.commit()
                    if cursor.lastrowid:
                        flight_fk = cursor.lastrowid
                    else:
                        flight_fk = 0
            except pymysql.err.ProgrammingError as e:
                logging.exception("Error: {}".format(e))
            except pymysql.err.IntegrityError as e:
                logging.exception("Error: {}".format(e))
            except TypeError as e:
                logging.exception("Error: {}".format(e))
            except:
                logging.exception("Unexpected error:", sys.exc_info()[0])

以上每 2 分钟对相同数据运行一次,并且应该只插入非重复项,因为 MySQL 会由于唯一的 ucid_takeofftime 索引而拒绝重复项。

MYSQL 信息,cb_flights table -

  `pk` int(11) NOT NULL AUTO_INCREMENT,
  `ucid` varchar(50) NOT NULL,
  `takeoff_time` datetime DEFAULT NULL,
  `end_time` datetime DEFAULT NULL,
  `end_event` varchar(45) DEFAULT NULL,
  `side` varchar(45) DEFAULT NULL,
  `kills` int(11) DEFAULT NULL,
  `type` varchar(45) DEFAULT NULL,
  `map_fk` int(11) DEFAULT NULL,
  `era_fk` int(11) DEFAULT NULL,
  `round_fk` int(11) DEFAULT NULL,
  PRIMARY KEY (`pk`),
  UNIQUE KEY `ucid_takeofftime` (`ucid`,`takeoff_time`),
  KEY `ucid_idx` (`ucid`) /*!80000 INVISIBLE */,
  KEY `end_event` (`end_event`) /*!80000 INVISIBLE */,
  KEY `side` (`side`)
) ENGINE=InnoDB AUTO_INCREMENT=76023132 DEFAULT CHARSET=utf8;

现在从 Python 代码插入到 table,有时可能需要 60 多秒。 我相信这可能与在 table 上创建锁的自动增量有关,如果是这样,我正在寻找解决方法。

innodb 信息-

innodb_autoinc_lock_mode    2
innodb_lock_wait_timeout    50

缓冲区最多或少使用了 70%。

感谢应用程序方面或 MySQL 方面的任何帮助。

编辑 为 cb_kills table 添加创建语句,它也用于插入,但据我所知没有问题,这是对第一个答案的评论的回应。

CREATE TABLE `cb_kills` (
  `pk` int(11) NOT NULL AUTO_INCREMENT,
  `time` datetime DEFAULT NULL,
  `killer_ucid` varchar(50) NOT NULL,
  `killer_side` varchar(10) DEFAULT NULL,
  `killer_unit` varchar(45) DEFAULT NULL,
  `victim_ucid` varchar(50) DEFAULT NULL,
  `victim_side` varchar(10) DEFAULT NULL,
  `victim_unit` varchar(45) DEFAULT NULL,
  `weapon` varchar(45) DEFAULT NULL,
  `flight_fk` int(11) NOT NULL,
  `kill_id` int(11) NOT NULL,
  PRIMARY KEY (`pk`),
  UNIQUE KEY `ucid_killid_flightfk_uniq` (`killer_ucid`,`flight_fk`,`kill_id`),
  KEY `flight_kills_fk_idx` (`flight_fk`),
  KEY `killer_ucid_fk_idx` (`killer_ucid`),
  KEY `victim_ucid_fk_idx` (`victim_ucid`),
  KEY `time_ucid_killid_uniq` (`time`,`killer_ucid`,`kill_id`),
  CONSTRAINT `flight_kills_fk` FOREIGN KEY (`flight_fk`) REFERENCES `cb_flights` (`pk`)
) ENGINE=InnoDB AUTO_INCREMENT=52698582 DEFAULT CHARSET=utf8;

您可以检查自动提交是否设置为 1,这会强制提交每一行并禁用它会使其速度更快

尝试批量插入而不是提交每个插入。

为此你应该检查一下 https://dev.mysql.com/doc/refman/8.0/en/optimizing-innodb-bulk-data-loading.html

然后做类似

的事情
data = [
('city 1', 'MAC', 'district 1', 16822),
('city 2', 'PSE', 'district 2', 15642),
('city 3', 'ZWE', 'district 3', 11642),
('city 4', 'USA', 'district 4', 14612),
('city 5', 'USA', 'district 5', 17672),
]

sql = "insert into city(name, countrycode, district, population) 
VALUES(%s, %s, %s, %s)"

number_of_rows = cursor.executemany(sql, data)
db.commit()

我想在这里介绍我为解决此问题而采用的一些方法。我不是 MySQL 方面的专家,但我认为这些步骤可以帮助任何想要找出锁等待超时原因的人。

所以我采取的故障排除步骤如下 -

1- 检查我是否可以在 MySQL 慢速日志中找到锁定我的 table 的相关查询。通常可以找到 运行 很长时间的查询,并锁定下面的信息和紧随其后的查询

# Time: 2020-01-28T17:31:48.634308Z
# User@Host: @ localhost [::1]  Id: 980397
# Query_time: 250.474040  Lock_time: 0.000000 Rows_sent: 10  Rows_examined: 195738

2- 以上应该提供了一些关于服务器中正在发生的事情以及可能需要等待很长时间的线索。接下来我 运行 以下 3 个查询来确定正在使用的内容:

  • 检查进程列表 运行ning -

show full processlist;

  • 检查当前正在使用的 tables -

show open tables where in_use>0;

  • 检查运行宁运行行动-

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`;

3- 上述 2 个步骤应该提供足够的信息,说明哪个查询正在锁定 table。在我这里的例子中,我有一个 运行 和 insert into <different table> select from <my locked table> 的 SP,当它插入到一个完全不同的 table 时,这个查询锁定了我的 table,因为 select 花费很长时间的操作。 为了解决这个问题,我将 SP 更改为使用临时 tables,现在虽然查询仍未完全优化,但我的 table.

上没有锁

在此处添加我如何 运行 临时 table 上的 SP 进行异步聚合更新。

CREATE DEFINER=`username`@`%` PROCEDURE `procedureName`()
BEGIN
    drop temporary table if exists scheme.temp1;
    drop temporary table if exists scheme.temp2;
    drop temporary table if exists scheme.temp3;
    create temporary table scheme.temp1 AS select * from scheme.live1;
    create temporary table scheme.temp2 AS select * from scheme.live2;
    create temporary table scheme.temp3 AS select * from scheme.live3;
    create temporary table scheme.emptytemp (
      `cName1` int(11) NOT NULL,
      `cName2` varchar(45) NOT NULL,
      `cName3` int(11) NOT NULL,
      `cName4` datetime NOT NULL,
      `cName5` datetime NOT NULL,
      KEY `cName1` (`cName1`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

    INSERT into scheme.emptytemp
    select t1.x,t2.y,t3.z
    from scheme.temp1 t1
    JOIN scheme.temp2 t2
    ON t1.x = t2.x
    JOIN scheme.temp3 t3
    ON t2.y = t3.y

    truncate table scheme.liveTable;
    INSERT into scheme.liveTable
    select * from scheme.emptytemp;
END

希望这对遇到此问题的任何人有所帮助