据我所知,DELETE FROM ... WHERE
会锁定表格。
现在,我在MariaDB中有一个巨大的InnoDB表,其大小为1TB +正在被使用,并且在搜索整个数据库以寻找要删除的行之前将其锁定是没有选择的。
有什么方法可以删除符合某些条件的行,而不是在删除时锁定它?
以下是针对此案例的更具体细节:
innodb_buffer_pool_size = 20G
INSERT
和SELECT
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时间戳,以毫秒为单位)为了完成任务,我自然会想出这个简单的查询:
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)
但这可能会锁定表格很长一段时间。如何在没有锁定表的情况下完成相同的任务,这样数据库仍可用于其他SELECT
和INSERT
查询?
答案 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
根据需要执行多次。在执行之间,其他查询可以进入并最小化影响。当然,在低负荷时间完成这项工作。