SELECT ... FOR UPDATE来自多个线程中的一个表

时间:2013-01-17 12:08:10

标签: mysql transactions innodb table-locking

我需要SELECT FOR UPDATE (resp. LOCK IN SHARE MODE)的帮助。

我有一个包含大约400,000条记录的表格,我需要在每一行上运行两个不同的处理函数。

表结构恰如其分:

data (
    `id`,
    `mtime`,  -- When was data1 set last
    `data1`,
    `data2` DEFAULT NULL,
    `priority1`,
    `priority2`,
    PRIMARY KEY `id`,
    INDEX (`mtime`),
    FOREIGN KEY ON `data2`
)

功能略有不同:

  • 第一个功能 - 必须在所有记录上循环运行(非常快),应根据priority1选择记录;设置data1mtime
  • 第二个功能 - 每个记录只需运行一次(非常慢),应根据priority2选择记录;设置data1mtime

他们不应该同时修改同一行,但是select可能会返回两行中的一行(priority1priority2具有不同的值)并且事务可以等待如果是这种情况(我希望这将是它阻止的唯一情况)。

我正在根据以下查询选择数据:

-- For the first function - not processed first, then the oldest,
-- the same age goes based on priority
SELECT id FROM data ORDER BY mtime IS NULL DESC, mtime, priority1 LIMIT 250 FOR UPDATE;

-- For the second function - only processed not processed order by priority
SELECT if FROM data ORDER BY priority2 WHERE data2 IS NULL LIMIT 50 FOR UPDATE;

但我遇到的是每次只有一次查询返回。

所以我的问题是

  • 是否可以在单独的一堆行(在同一个表中)中的两个单独的事务中获取两个单独的锁?
  • 我是否在第一次和第二次查询之间发生了很多冲突(我在调试时遇到了麻烦,任何有关如何调试SELECT ... FROM (SELECT ...) WHERE ... IN (SELECT)的提示都会受到赞赏)?
  • ORDER BY ... LIMIT ...会导致任何问题吗?
  • 索引和密钥是否会导致任何问题?

2 个答案:

答案 0 :(得分:3)

在深入了解之前要检查的关键事项:

  • 确保表引擎 InnoDB ,否则“for update”不会锁定该行,因为没有事务。
  • 确保您正确使用“更新”功能。如果您选择要更新的内容,则会锁定该事务。 虽然其他交易可能能够读取该行,但在原始锁定交易释放锁定之前,任何其他交易都无法选择更新,更新或删除该行。
  • 为了保持清洁,请尝试使用“START TRANSACTION”显式启动事务,运行select“for update”,对要返回的记录执行任何操作,并通过显式执行“ COMMIT“关闭交易。

根据我的判断,订单和限制对您遇到的问题没有任何影响,Select将返回的是将被锁定的行。

回答你的问题:

        
  1. 是否可以在单独的一堆行(在同一个表中)中的两个单独的事务中获取两个单独的锁?
    是的,但不是在同一行。锁只能一次存在于一个事务中的行级别。     
  2. 我在第一次和第二次查询之间有多少次碰撞(我有麻烦调试,有关如何调试SELECT ... FROM(SELECT ...)WHERE ... IN的任何提示(选择)将不胜感激)?
    计算行锁定的时间可能很短,这将延迟第二个查询,但是除非您一次运行数百个这样的选择更新,否则不会导致任何重大或明显的延迟。< / LI>     
  3. 可以订购......限制......导致任何问题吗? 不是我的经验。它们应该像在正常的选择语句中一样工作。
  4.     
  5. 索引和密钥是否会导致任何问题?
    索引应该始终存在以确保足够的性能,但它们不应该导致获得锁定的任何问题。

答案 1 :(得分:0)

接受答案中的所有分数似乎都不错,但低于2分: &#34; Select将返回的内容将是被锁定的行。&#34; &安培; &#34; 索引和密钥是否会导致任何问题? 但他们不应该因为获得锁定而导致任何问题。&#34;

而是在决定选择和返回哪些行时,DB内部读取的所有行都将被锁定。例如,下面的查询将锁定表的所有行,但可能只选择并返回几行: select * from table from non_primary_non_indexed_column =?更新 由于没有索引,因此DB必须读取整个表以搜索所需的行,从而锁定整个表。

如果只想锁定一行,则需要在where子句中指定其主键或索引列。因此,在仅锁定适当的行的情况下,索引变得非常重要。

这是一个很好的参考 - https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html