在不锁定MariaDB / MySQL的情况下删除?(InnoDB)

use*_*253 3 mysql database mariadb

据我所知,DELETE FROM ... WHERE在桌子上发出了锁。

现在,我在MariaDB中有一个正在使用的巨大的InnoDB表,大小为1TB +,正在使用它,直到在整个数据库中搜索要删除的行之后才锁定它。

有什么方法可以删除符合特定条件的行而不在删除发生时锁定它?

这是此情况的更多详细信息:

  • 服务器正在从Debian Stretch存储库运行MariaDB 10.1.22-3
  • 该服务器具有32 GB的ram和 innodb_buffer_pool_size = 20G
  • 该数据库的大小为1TB +,INSERT并且SELECT始终有很多active 和。
  • 整个数据库仅包含2个表:
    • 一张用于实际数据的表(基本上具有如下结构data (BIGINT id, LONGTEXT data):(其中data有大量JSON。我知道这不是一个完美的关系数据库模型,但是JSON来自第三方,它非常复杂,并且可能包含第三方随时更改结构,恕不另行通知)
    • 还有一张表,用于满足SELECTs的某种“索引” 。(简化的示例,其结构可能类似于data_index (BIGINT id, INT userId, INT itemId, BIGINT timestamp),因此我可以SELECT在userId和itemId上使用,并加入实际数据。(时间戳是unix时间戳,以毫秒为单位)
  • 就像我说的那样,数据只能存储有限的时间。因此,基本上现在我想创建一个每天运行一次的cronjob,以删除7天以上的行。

为了完成任务,我自然会想到一个简单的查询:

DELETE `data`, `data_index`
FROM `data_index`
LEFT JOIN `data` ON `data`.`id` = `data_index`.`id`
WHERE `timestamp` > (NOW() * 1000) - (7 * 24 * 60 * 60 * 1000)
Run Code Online (Sandbox Code Playgroud)

但这可能会锁定表很长时间。我怎么能完成相同的任务,而不锁定表,所以数据库仍然是其他功能SELECTINSERT查询?

Bil*_*win 5

不,如果不锁定检查的行,则无法删除。

但是您可以通过在timestamp要搜索的列上创建索引来最大程度地减少检查的行数。

这还将针对您可能尝试在表末尾插入的潜在行创建间隙锁,以确保新行不会影响DELETE。

在InnoDB中,普通的写锁(如DELETE创建的锁)不会阻止读取。并发事务仍然可以读取行,甚至是您要删除的行。

普通的写锁不会锁定整个表。好吧,它用意图锁来锁定表,目的锁只是防止其他表锁,例如ALTER TABLE或DROP TABLE所要求的那些。换句话说,当表正在进行任何读取或写入操作时,您不能更改/删除该表。

您可能喜欢我的演示文稿:InnoDB Locking用Stick Figures解释了


Fra*_*ezo 4

也许我错了,但在https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html上我读到它会产生行锁,而不是表锁。

无论如何你可以尝试

删除...从...哪里...限制x

并根据需要执行多次。在执行之间,其他查询可以进入并最大限度地减少影响。当然,请在低负载时间进行这项工作。