MySQL-在不锁定行的情况下更新表行

MySQL-在不锁定行的情况下更新表行,mysql,batch-processing,rowlocking,Mysql,Batch Processing,Rowlocking,我有一个要求,我们需要更新行,而不需要在更新时保持锁定 以下是要求的详细信息,我们将每5分钟对一个表运行一次批处理update blogs set is_visible=1,其中一些条件此查询将在数百万条记录上运行,因此我们不希望在更新期间阻止所有行的写入 我完全理解没有写锁的含义,这对我们来说很好,因为只有通过这个批处理才能更新is_visible列,没有其他线程会更新这个列。另一方面,我们不想阻止对同一表中其他列的大量更新。最佳做法是在更新可能与其他事务同时发生时始终获取特定的锁。如果您的存

我有一个要求,我们需要更新行,而不需要在更新时保持锁定

以下是要求的详细信息,我们将每5分钟对一个表运行一次批处理
update blogs set is_visible=1,其中一些条件
此查询将在数百万条记录上运行,因此我们不希望在更新期间阻止所有行的写入


我完全理解没有写锁的含义,这对我们来说很好,因为只有通过这个批处理才能更新is_visible列,没有其他线程会更新这个列。另一方面,我们不想阻止对同一表中其他列的大量更新。最佳做法是在更新可能与其他事务同时发生时始终获取特定的锁。如果您的存储引擎是MyISAM,那么MySQL将在更新期间锁定整个表,对此您无能为力。如果存储引擎是InnoDB,那么MySQL可能只会对更新所针对的记录设置一个独占的IX锁,但在这种情况下需要注意。要实现这一点,您要做的第一件事是
SELECT。。。对于更新

SELECT * FROM blogs WHERE <some conditions> FOR UPDATE;
即使有了这样的索引,InnoDB仍然可以对索引值之间的记录应用间隙锁,以确保执行
可重复读取
契约


因此,您可以在
WHERE
子句中涉及的列上添加索引,以优化InnoDB上的更新。

首先,如果您默认使用MySQL的InnoDB存储引擎,那么除了通过运行将事务隔离级别设置为READ UNCOMMITTED之外,您无法在没有行锁的情况下更新数据

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
但是,我不认为数据库行为是您所期望的,因为在这种情况下允许脏读。“未提交的阅读”在实践中很少有用

为了补充@Tim的答案,在where子句中使用的列上有一个唯一的索引确实是一个好主意。但是,也请注意,不能绝对保证优化器最终会使用创建的索引选择这样的执行计划。它可能有效,也可能无效,这取决于具体情况

对于您的情况,您可以做的是将长事务拆分为多个短事务。与其一次更新数百万行,不如每次只扫描数千行。当每个短事务提交或回滚时,会释放X锁,使并发更新有机会继续进行

顺便说一句,我假设您的批处理的优先级低于其他在线处理,因此可以将其安排在高峰时间之外,以进一步将影响降至最低


另外,IX锁不在记录本身上,而是附加到更高粒度的表对象上。即使使用可重复读取事务隔离级别,当查询使用唯一索引时也没有间隙锁定。

我不确定我的问题是否正确?我不希望在更新期间发生行锁定,所以使用`select。。。For update`将锁定表。我的问题是,有没有一种方法可以在不使用行锁的情况下更新行?这只适用于
MyISAM
。在InnoDB上,
FOR UPDATE
不会锁定整个表,前提是您具有正确的唯一索引设置。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;