Mysql

where子句不匹配時並發更新查詢鎖定行

  • December 26, 2018

我的應用程序向 Slack 發送消息。在極少數情況下,我們可能需要撤回消息。messageId這些撤回是通過為迄今為止創建的每個作業排隊來處理的。

在大約一周前的最後一次撤稿中,我注意到我們看到了大約 2k:

try restarting transaction (SQL: update messagesetdeleted_at = 2018-12-04 04:47:44 where (slack_channel_id = xxxxxxxxxxxxxxxx and message_id = xxxxxxxxxxxxxxxx))"

似乎隊列作業(絕對同時發生)正在互相踩踏。我的期望是這個查詢只會在它需要的單個行上加鎖(我們在 和 上有一個複合唯一索引)slack_server_id,但似乎不止一項工作正在鎖定這條記錄。slack_channel_id``message_id

where為什麼這些並發更新查詢會鎖定與子句不匹配的行?

CREATE TABLE `messages` (
 `slack_id` bigint(20) unsigned NOT NULL,
 `slack_channel_id` bigint(20) unsigned NOT NULL,
 `message_id` bigint(20) unsigned NOT NULL,
 `slack_message_id` bigint(20) unsigned DEFAULT NULL,
 `premium` tinyint(1) NOT NULL DEFAULT '0',
 `created_at` timestamp NULL DEFAULT NULL,
 `updated_at` timestamp NULL DEFAULT NULL,
 `deleted_at` timestamp NULL DEFAULT NULL,
 UNIQUE KEY `slack_message_slack_id_channel_id_message_id_unique` (`slack_id`,`slack_channel_id `,`message_id`),
 KEY `slack_message_message_id_foreign` (`message_id`),
 CONSTRAINT `slack_message_slack_id_foreign` FOREIGN KEY (`slack_id`) REFERENCES `slacks` (`id`),
 CONSTRAINT `slack_message_message_id_foreign` FOREIGN KEY (`message_id`) REFERENCES `messages` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

更新

我添加了一個id自動增量主列,但它沒有解決事務問題。

學習索引的一課。 INDEX(a,b,c)不是最優WHERE a=1 AND c=2。這是因為只會使用索引的最左邊的列;不能有任何跳過列(b在本例中)。

回到你的問題。

INDEX(slack_channel_id, message_id)

是需要的,並且

INDEX(`slack_id`,`slack_channel_id `,`message_id`)

一點用都沒有slack_id擋路了。

KEY `slack_message_message_id_foreign` (`message_id`),

部分有用 - 即用於將搜尋範圍縮小到具有所需message_id.

關於建構最佳索引的食譜。

引用自:https://dba.stackexchange.com/questions/224484