В MySQL у меня есть две таблицы innodb, небольшая критическая таблица, которая должна быть всегда доступна для чтения / записи. Назовите это mission_critical. У меня есть большая таблица (> 10 миллионов строк), называемая big_table. Мне нужно обновить big_table, например:
update mission_critical c, big_table b
set
b.something = c.something_else
where b.refID=c.id
Этот запрос может занять более часа, но это создает блокировку записи в таблице mission_critical. Есть ли способ, которым я могу сказать mysql: «Я не хочу блокировать mission_critical», чтобы в эту таблицу можно было записать?
Я понимаю, что это не идеально с точки зрения транзакций. Единственный обходной путь, о котором я могу подумать сейчас, - это сделать копию маленькой таблицы mission_critical и выполнить обновление из нее (которая меня не интересует, заблокирована), но я бы предпочел этого не делать, если есть способ сделать MySQL изначально справляется с этим более изящно.
Редактировать : некоторые уточнения
Блокируется не таблица, а все записи в mission_critical, которые блокируются, поскольку все они в основном сканируются обновлением. Я не предполагаю этого; Симптом заключается в том, что когда пользователь входит в онлайн-систему, он пытается обновить столбец datetime в mission_critical, чтобы обновить последний раз, когда они вошли в систему. Эти запросы умирают из-за ошибки ожидания превышения времени ожидания блокировки во время выполнения вышеуказанного запроса. Если я убью приведенный выше запрос, все ожидающие запросы будут выполнены немедленно.
mission_critical.id и big_table.refID оба проиндексированы.
Соответствующие части операторов создания для каждой таблицы:
mission_critical:
CREATE TABLE `mission_critical` (
`intID` int(11) NOT NULL AUTO_INCREMENT,
`id` smallint(6) DEFAULT NULL,
`something_else` varchar(50) NOT NULL,
`lastLoginDate` datetime DEFAULT NULL,
PRIMARY KEY (`intID`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `something_else` (`something_else`),
) ENGINE=InnoDB AUTO_INCREMENT=1432 DEFAULT CHARSET=latin1
big_table:
CREATE TABLE `big_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`postDate` date DEFAULT NULL,
`postTime` int(11) DEFAULT NULL,
`refID` smallint(6) DEFAULT NULL,
`something` varchar(50) NOT NULL,
`change` decimal(20,2) NOT NULL
PRIMARY KEY (`id`),
KEY `refID` (`refID`),
KEY `postDate` (`postDate`),
) ENGINE=InnoDB AUTO_INCREMENT=138139125 DEFAULT CHARSET=latin1
Объяснение запроса:
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+
| 1 | SIMPLE | mission_critical | | ALL | id | | | | 774 | 100 | Using where |
| 1 | UPDATE | big_table | | ref | refID | refID | 3 | db.mission_critical.something_else | 7475 | 100 | |
+----+-------------+------------------+------------+------+---------------+-------+---------+------------------------------------+------+----------+-------------+