Тупик в mysql при добавлении внешнего ключа - PullRequest
3 голосов
/ 18 апреля 2019

В нашей базе данных есть таблица с именем company_competitors. есть работа, которая усекает и загружает эту таблицу ежедневно. Таблица имеет два столбца company_id и competitor_id, оба ссылаются на другую таблицу companies.

CREATE TABLE `company_competitors` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `company_id` int(11) DEFAULT NULL,
  `competitor_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_rails_company_id_c1ac450a` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`),
  CONSTRAINT `fk_rails_competitor_id_772a45c6` FOREIGN KEY (`competitor_id`) REFERENCES `companies` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=268477 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

Шаги, включенные в усечение и загрузку:

  1. создать новую таблицу company_competitors_new
  2. добавить ограничения внешнего ключа для обоих столбцов (company_id, competitor_id) по одному.
  3. загрузить данные в новую таблицу.
  4. поменяйте местами таблицы company_competitors и company_competitors_new.

Запросы:

"CREATE TABLE company_competitors_new LIKE company_competitors;

alter table company_competitors_new ADD CONSTRAINT fk_rails_company_id_53f8f57a foreign key (company_id) references companies(id);'

Некоторые компании могут получить доступ к таблице компаний при добавлении внешнего ключа. Таким образом, при выполнении второго запроса база данных застревает в тупике, и никакие запросы к таблице компаний не выполняются.

show full processlist показывает все запросы, говорящие Waiting to acquire Metadata lock, и мне нужно убить все запросы на выборку, чтобы завершить добавление внешнего ключа.

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

1 Ответ

2 голосов
/ 30 апреля 2019

Лично, если тупик возникает редко, я просто заново готовлю новую транзакцию и перезапускаю запросы (это не самое желаемое решение, но работает в этом случае). Однако, если ваш тупик появляется системно, как вы упомянули, вы можете проверить больше info с командой SHOW ENGINE INNODB STATUS, чтобы увидеть некоторые детали недавних взаимоблокировок. Мой совет также поставить блок, который создает company_competitors_new между

SET foreign_key_checks = 0;

... (запросы) ...

SET foreign_key_checks = 1;

...