【问题标题】:Multiple UPDATE in single transaction vs one UPDATE with big WHERE clause单个事务中的多个 UPDATE 与一个带有大 WHERE 子句的 UPDATE
【发布时间】:2014-09-08 13:19:13
【问题描述】:

什么更有效:

START TRANSACTION
UPDATE mytable SET foo = 'bar' WHERE (col1 = 813242) AND (col2 = 25343);
UPDATE mytable SET foo = 'bar' WHERE (col1 = 312643) AND (col2 = 8353);
UPDATE mytable SET foo = 'bar' WHERE (col1 = 843564) AND (col2 = 41233);
UPDATE mytable SET foo = 'bar' WHERE (col1 = 321312) AND (col2 = 5325);
UPDATE mytable SET foo = 'bar' WHERE (col1 = 554235) AND (col2 = 6321);
... x 10,000 times or more
COMMIT;

UPDATE mytable SET foo = 'bar' WHERE
((col1 = 16344) AND (col2 = 5456)) OR
((col1 = 42134) AND (col2 = 5436)) OR
((col1 = 84563) AND (col2 = 2321)) OR
((col1 = 43216) AND (col2 = 4267)) OR
((col1 = 53248) AND (col2 = 6234)) OR
... x 10,000 times or more

假设我在 (col1,col2) 上有 UNIQUE 索引

所以我的猜测是第一个选项很好,因为索引但是它被分成多个查询,第二个选项很好,因为它只是一个查询,但另一方面它会进行全表扫描

这是EXPLAIN,当不使用OR时:

type: ref, possible_keys: myindex_UNIQUE, key: myindex_UNIQUE, ref: const

这是EXPLAIN,当使用OR时:

type: ALL, possible_keys: myindex_UNIQUE, key: null, ref: null

查询WHERE子句有限制吗?

我的目标是最大速度

【问题讨论】:

  • 所以模式是col1 = N AND col2 = N+1(即col2 = col1 + 1?这可能是可能的,并且通过连接可能更有效......
  • @MichaelBerkowski 没有模式,这只是一个例子
  • 彼得,你是重复 10000 次 UPDATE 语句还是从 START 到 COMMIT 的块?
  • @Peter:我知道这不是直接的答案,但我建议您使用无事务解决方案,如果这是可以接受的并且如果要更新许多记录,则使用单独的 UPDATE 语句每个查询很少。长时间的交易不是好事。
  • Hmmm.. 一种可能的解决方案是将 API 调用的结果插入到临时/帮助表(可能带有索引)中,并将该表用作更新查询的过滤器。如果您的表包含的行数比要更新的行数多得多,这可能会有所帮助。您可以在更新后截断或删除临时/帮助表。临时表可以使用基于内存的存储引擎来最大化性能。

标签: mysql


【解决方案1】:

根据cmets中的对话,一个可能的解决方案:

如果您有一个大表和一个值列表来标识要更新的行,您可以为值列表创建一个帮助表。

根据问题中的示例,表格可能是这样的:

CREATE TABLE mytable_operation (
    col1 INT
  , col2 INT
) ENGINE = MEMORY;

请注意,create 语句包含ENGINE = MEMORY 提示,因此该表将存储在内存中而不是磁盘中。

在更新之前将值加载到此表中。

将所有值加载到辅助表中后,您可以使用以下查询更新生产表中的值。

UPDATE
  mytable
SET
  foo = 'bar'
WHERE
  EXISTS (SELECT 1 FROM mytable_operation MO WHERE mytable.col1 = MO.col1 AND mytable.col2 = MO.col2)

当然,您可以使用任何 DML 语句来操作生产数据。 (更新连接,DELETEINSERT..ON DUPLICATE KEY 等)

完成数据操作后,您可以截断或删除辅助表。

如果生产表中的行数稍大,则此解决方案可能比问题中的解决方案更快。

【讨论】:

    【解决方案2】:

    我认为理论上第二个会更快,但这只是一个有根据的猜测。

    这是一个语句,因此它可能需要更少的解析、更少的初始化和更少的往返。

    第一个可能更快,因为它使用索引来查找记录。但是 10.000 次索引查找可能也会比全表扫描慢,所以我认为这个优势也没有了。

    多个语句可能变慢的一个原因是,当您在程序的循环中运行单独的更新时。在这种情况下,您的请求/响应开销是 10.000 倍。

    只要您不这样做并且只是将更新作为单个请求发送,我认为性能将是相似的,任何差异将取决于服务器的硬件和配置,以及当前负载,表中的数据量以及您更新的行数(或者它总是恰好是 10.000?)。总而言之,我无法给你一个确切的答案,但我希望我已经让你深入了解了影响此性能的一些因素。

    【讨论】:

      【解决方案3】:

      在插入/更新时使用 nosql 引擎以获得最快的结果

      如果您想查看您的索引是如何工作的,请将更新替换为 SELECT 并使用说明运行它。这应该让您了解索引是否以您想要的方式使用

      EXPLAIN how to

      并且不要忘记索引通常会减慢任何更新/插入的速度 它仅在 where 子句中有用

      【讨论】:

      • 索引会减慢插入速度,但更新语句通常也有 where 子句。如果索引位于更新的字段而不是搜索的字段上,则索引会减慢更新速度。基本上,如果索引导致索引发生变化,则索引会减慢 DML 语句的速度。
      • 切换到 noSQL 不是一种选择。我进行了 EXPLAIN 查询,因为我怀疑只有第一个选项正确使用索引
      猜你喜欢
      • 1970-01-01
      • 2012-11-20
      • 2013-06-28
      • 2018-09-01
      • 1970-01-01
      • 2020-04-12
      • 1970-01-01
      • 2013-10-28
      • 1970-01-01
      相关资源
      最近更新 更多