Mysql 性能:哪个查询会花费更多时间?

Posted

技术标签:

【中文标题】Mysql 性能:哪个查询会花费更多时间?【英文标题】:Mysql Performance: Which of the query will take more time? 【发布时间】:2017-12-27 17:10:58 【问题描述】:

我有两张桌子: 1. 1000万左右数据的用户表 列:token_type、cust_id(主要) 2. pm_tmp 表,200k 数据 列:id(Primary | AutoIncrement), user_id

user_id 是 cust_id 的外键

第一种方法/查询:

update user set token_type='PRIME'
where cust_id in (select user_id from pm_tmp where id between 1 AND 60000);

第二种方法/查询:在这里,我们将针对 60000 条记录分别针对不同的 cust_id 运行以下查询:

update user set token_type='PRIME' where cust_id='1111110';

【问题讨论】:

当你测量它时,你得到了什么结果? 第二种方法花费的时间更少。但我正试图找出原因。 那是因为,第一个查询需要为您的 innodb 缓冲池提供足够的内存才能快速执行。第二个是单个事务查询将需要相对较少的时间。 【参考方案1】:

理论上,第一次查询的时间会更短,因为它涉及的提交次数更少,进而索引重建的次数也更少。但是,我建议使用第二个选项,因为它更受控制并且看起来时间更短,您可以考虑并行执行 2 个单独的集合。

注意:第一个查询需要为 mysql 缓冲区提供足够的内存才能快速执行。第二个查询是一组独立的单个事务查询,它们需要的内存相对较少,因此如果在内存有限的环境中执行,它们会显得更快。

好吧,你也可以这样重写第一个查询。

update user u, pm_tmp p set u.token_type='PRIME' where u.cust_id=p.id and p.in <60000;

【讨论】:

【参考方案2】:

某些版本的 MySQL 无法优化 in。我会推荐:

update user u join
       pm_tmp pt
       on u.cust_id = pt.user_id and pt.id between 1 AND 60000
    set u.token_type = 'PRIME' ;

(注意:这假设cust_idpm_temp 中没有重复。如果可能,您将需要一个select distinct 子查询。)

您的第二个版本通常会慢很多,因为它需要执行数千个查询而不是一个。一个考虑因素可能是update。随着更新次数的增加,日志记录和锁定可能会变得更加复杂。我实际上对 MySQL 内部的了解还不够,无法知道这是否会对性能产生重大影响。

【讨论】:

【参考方案3】:

IN ( SELECT ... ) 优化不佳。 (我无法提供具体细节,因为 UPDATEIN 在一些最新版本的 MySQL 中得到了更好的优化。)只要说“避免 IN ( SELECT ... )”就足够了。

您的第一句话应该说“行”而不是“列”。

回到问题的其余部分。 60K 太大了。我只推荐 1000 个。除此之外,Gordon's Answer 可能是最好的。

但是……你没有使用OFFSET不要尝试使用它;当您越走越远时,它会降低性能。

另一件事。 COMMIT 在每个块之后。否则你会建立一个巨大的撤销日志;这增加了成本。 (这也是 1K 可能比 60K 快的原因。)

但是等等!你为什么要更新一张大桌子?这通常是模式设计不佳的标志。请解释一下数据流。

也许您已经计算出哪些项目要标记为“主要”?好吧,您可以保留该列表并在SELECTs 中执行JOINs 以在阅读时发现素数。这完全消除了有问题的UPDATE。当然,JOIN 有点贵,但并不高。

【讨论】:

以上是关于Mysql 性能:哪个查询会花费更多时间?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL慢查询分析

COUNT(id) 查询花费的时间太长,哪些性能增强可能会有所帮助?

如果表中的行数很大(200 万),NDB cluster7.5(MySQL 5.7)在获取数据时会花费更多时间

详解Oracle partition分区表

MySQL之查询性能优化

Mysql 查询性能。哪个最好?