在MariaDB / MySQL中没有锁定删除?`(InnoDB)

时间:2017-05-20 21:54:51

标签: 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 +,并且始终有很多有效INSERTSELECT
  • 整个数据库只包含2个表:
    • 实际数据的一个表(基本上有data (BIGINT id, LONGTEXT data)之类的结构(其中data是JSON的一大块。我知道这不是一个完美的关系数据库模型,而是JSON来自第三方,它非常复杂,可能随时包含来自第三方的结构变更,恕不另行通知)
    • 还有一张表用于某种索引'满足SELECT s。 (简化示例,这可能有data_index (BIGINT id, INT userId, INT itemId, BIGINT timestamp)之类的结构,因此我可以在userId和itemId上使用SELECT,并加入实际数据。(timestamp是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)

但这可能会锁定表格很长一段时间。如何在没有锁定表的情况下完成相同的任务,这样数据库仍可用于其他SELECTINSERT查询?

3 个答案:

答案 0 :(得分:3)

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

但是,您可以通过在要搜索的timestamp列上创建索引来最小化检查的行数。

这也会针对您可能尝试在表末尾插入的潜在行创建gap locks,以确保新行不会影响DELETE。

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

普通写锁不会锁定整个表。好吧,它使用intention lock锁定表,这只会阻止其他表锁,例如ALTER TABLE或DROP TABLE所需的表锁。换句话说,当进行任何读取或写入时,您不能对表进行ALTER / DROP。

您可能会喜欢我的演示文稿:InnoDB Locking Explained with Stick Figures

答案 1 :(得分:2)

(NOW() * 1000) - (7 * 24 * 60 * 60 * 1000)看起来不是一个有效的时间。它是20170519568613000,看起来像DATETIME和某种毫秒的混合。 也许你想要UNIX_TIMESTAMP() * 1000 - (7 * 24 * 60 * 60 * 1000) = 1494742589000

您希望删除多少行?如果它是一个大数字,那么考虑分区,或deleting in chunks

答案 2 :(得分:1)

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

无论如何你可以尝试

DELETE ... FROM ... WHERE ... LIMIT x

根据需要执行多次。在执行之间,其他查询可以进入并最小化影响。当然,在低负荷时间完成这项工作。