我有两个表:1。用户表有大约1000万个数据列:token_type,cust_id(主要)2。pm_tmp表有200k数据列:id(主要|自动增量),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';
从理论上讲,第一个查询的时间会更短,因为它涉及的提交次数更少,而且索引重建次数也更少。但是,我会建议使用第二个选项,因为它更受控制,并且看起来时间更少,你可以考虑执行2个单独的套装parellelly。
注意:第一个查询需要为mysql缓冲区配置足够的内存才能快速执行。第二个查询是独立的单个事务查询集,它们需要相对较少的内存,因此如果在有限的内存环境中执行则会更快。
好吧,你也可以用这种方式重写第一个查询。
update user u, pm_tmp p set u.token_type='PRIME' where u.cust_id=p.id and p.in <60000;
某些版本的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_id
中没有重复pm_temp
。如果可能,你需要一个select distinct
子查询。)
您的第二个版本通常会慢得多,因为它需要执行数千个查询而不是一个。一个考虑因素可能是update
。随着更新次数的增加,日志记录和锁定可能会变得更加复杂。我对MySQL内部实际上并不了解,知道这是否会对性能产生重大影响。
IN ( SELECT ... )
优化不佳。 (我无法提供具体细节因为UPDATE
和IN
在最近的一些MySQL版本中得到了更好的优化。)只需说“避免IN ( SELECT ... )
”。
你的第一句话应该是“行”而不是“列”。
回到剩下的问题。 60K太大了。我建议只有1000.除此之外,戈登的答案可能是最好的。
但是......你没有使用OFFSET
;不要试图使用它;随着你走得越来越远,它会扼杀性能。
另一件事。 COMMIT
每个块后。否则你会建立一个巨大的撤销日志;这增加了成本。 (这也是为什么1K可能比60K更快的原因。)
可是等等!你为什么要更新一张大桌子?这通常是糟糕的架构设计的标志。请解释数据流。
也许您已计算出哪些项目标记为“素数”?那么,你可以保持这个列表并在JOINs
做SELECTs
,以便在阅读时发现素数。这完全消除了有问题的UPDATE
。当然,JOIN
花费了一些东西,但并不多。