Mysql превышен тайм-аут ожидания блокировки - автоинкремент - PullRequest
1 голос
/ 01 февраля 2020

У меня возникла проблема с приложением, из-за которой таблица MySQL была заблокирована из-за вставок, которые занимают много времени, после просмотра статей в Интернете кажется, что это связано с автоматическим приращением, информация ниже -

Python, который вставляет данные (к сожалению, строка за раз, так как мне нужен автоматически увеличенный идентификатор для справки при будущих вставках) -

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 info, таблица cb_flights -

  `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 код, иногда может занять более 60 секунд. Я полагаю, это может быть связано с автоматическим приращением, которое создает блокировку таблицы, если это так, я ищу обходной путь.

innodb info -

innodb_autoinc_lock_mode    2
innodb_lock_wait_timeout    50

буфер используется до 70% больше или меньше.

Оцените любую помощь в этом, либо со стороны приложения, либо со стороны MySQL.

EDIT Добавление оператора create для таблицы cb_kills, которая также используется со вставками, но без проблем, насколько я вижу, это в ответ на комментарий к 1-му ответу.

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;

Ответы [ 2 ]

1 голос
/ 01 февраля 2020

Вы можете проверить, установлен ли autocommit на 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()
0 голосов
/ 04 февраля 2020

Я хочу рассказать о некоторых способах решения этой проблемы. Я не являюсь экспертом в MySQL, но я думаю, что эти шаги могут помочь любому, кто хочет выяснить, почему у него есть тайм-ауты ожидания блокировки.

Итак, шаги по устранению неполадок, которые я предпринял, следующие:

1- Проверьте, могу ли я найти в MySQL медленном журнале соответствующий запрос, блокирующий мою таблицу. Обычно можно найти запросы, которые выполняются в течение длительного времени, а также блокируются с помощью приведенной ниже информации и запроса сразу после него

# 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 запроса, чтобы определить, что используется:

  • проверить список процессов, в которых выполняется процесс -

show full processlist;

  • проверка таблиц, используемых в настоящее время -

show open tables where in_use>0;

  • проверка выполнения транзакций -

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

3- Вышеприведенные 2 шага должны дать достаточно информации о том, какой запрос блокирует таблицы. в моем случае у меня был SP с insert into <different table> select from <my locked table>, когда он вставлялся в совершенно другую таблицу, этот запрос блокировал мою таблицу из-за операции выбора, которая заняла много времени. Чтобы обойти это, я изменил SP для работы с временными таблицами, и теперь, хотя запрос все еще не полностью оптимизирован, в моей таблице нет блокировок.

Добавление сюда, как я запускаю SP для временных таблиц для asyn c агрегированные обновления.

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

Надеюсь, это поможет всем, кто столкнулся с этой проблемой

...