【问题标题】:mysql how to update transaction of where clouse with 100,000 different conditionsmysql如何用100,000个不同的条件更新where子句的事务
【发布时间】:2021-03-29 16:58:45
【问题描述】:

在我的应用程序中,我允许使用 CSV 文件更新用户数据,最大限制为 100K 行。

csv 文件中的每一行都包含c_id,a_id, country_code

用户上传一个 CSV 文件,然后我从该文件创建一个查询

到目前为止一切正常

问题是我的表变大了,现在包含 69,123,914 行(我上次检查时)

现在执行时间大约需要 5 分钟

在这种情况下,最佳做法是什么?

这是表结构

Feild Type null Key Default extra
c_id bigint(20) NO PRI null
a_id int(11) NO PRI null
country_code varchar(2) NO PRI null
last_update timestamp NO "" CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
created_time timestamp NO "" CURRENT_TIMESTAMP
is_deleted tinyint(1) NO "" 0

这是从 CSV 行生成的查询

UPDATE my_table
SET    is_deleted = 1
WHERE  is_deleted = 0
AND (
    (c_id = '1' AND country_code = 'TH' AND a_id = '-1')
    OR (c_id = '1' AND country_code = 'RO' AND a_id = '-1')
    OR (c_id = '1' AND country_code = 'PT' AND a_id = '-1')
    OR (c_id = '2' AND country_code = 'JM' AND a_id = '-1')
    OR (c_id = '35' AND country_code = 'AM' AND a_id = '-1')
    OR (c_id = '77' AND country_code = 'BA' AND a_id = '-1')
    OR (c_id = '77' AND country_code = 'MD' AND a_id = '-1')
    OR (c_id = '77' AND country_code = 'LT' AND a_id = '-1')
    OR (c_id = '123' AND country_code = 'TT' AND a_id = '-1')
    OR (..... until 100k) ` 

这是执行计划

Operation Params rows raw des
INDEX_SCAN (range) table: my_table; index: PRIMARY; 100,000 Using where

【问题讨论】:

  • 我会将 CSV 加载到一个表中,然后加入该表,而不是动态创建一个巨大的 WHERE 子句。
  • 问题在于数据库执行时间,而不是查询构建
  • 如果您不想使用中间表,那么只需将您的动态查询至少转换为UPDATE my_table SET is_deleted = 1 WHERE is_deleted = 0 and (c_id, country_code, a_id) IN ((8338731, 'TH', -1), (8338731, 'RO', -1), ...)(c_id, country_code, a_id) 索引的存在将会改善。
  • 或(.....直到 100k - 这是否意味着每个 c_id = 8338731 ?只有 100k 中的一部分会被更新?
  • 附言。我认为删除 WHERE is_deleted = 0 不会降低性能 - MySQL 只更新实际更改的值,而不是全部更改。

标签: mysql sql optimization


【解决方案1】:

根据@Bee_Riii 的上述评论,您应该创建一个包含以下字段的新表:

c_id    | country_code | a_id
8338731 | TH           | -1
8338731 | RO           | -1
...

然后,改写您的更新查询以添加逻辑以断言此查找表中存在给定记录:

UPDATE my_table t1
SET is_deleted = 1
WHERE
    is_deleted = 0 AND
    (c_id, country_code, a_id) IN (SELECT c_id, country_code, a_id
                                   FROM lookupTable);

可以通过添加适当的索引来优化查找的性能:

CREATE INDEX idx ON lookupTable (c_id, country_code, a_id);

【讨论】:

  • 多表 UPDATE 语法在这种情况下更加明显。 UPDATE my_table t1 JOIN lookupTable t2 USING (c_id, country_code, a_id) SET t1.is_deleted = 1 WHERE t1.is_deleted = 0.
  • @Akina 你说得对,我也可以使用更新连接。我想我的目的是使查询尽可能接近原始查询。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多