如何更新7000万的数据,你会了吗?

点击蓝色“有关SQL”关注我哟

加个“星标”,天天与10000人一起快乐成长

前两天,我们微信群的小姐姐提出一个非常好的SQL问题。

更新7000万数据表的一个字段,最好的方法是什么

这个问题,是我的面试必考题,占总分值的90%. 从 128位历史面试者的回答来看,足够筛掉很多上来就要30K的5年+程序员,甚至很多10年+。

非常简单的一个需求,考查的并不是一个简单的SQL功底,而是对整个数据库体系的理解。注意,如果是老读者,你们对体系两字,印象应该非常深刻。

围绕这个话题,微信群炸了。似乎,每次只要小姐姐提问,讨论都异常热烈,比我发红包还燥。我百思不得其解,谁来回答我


一个人,可以走得很快。一群人,才可以走得更远

同样解决一个问题,你想到的方法是A和B。其他积极思考的人,一定还能想到C,D,甚至E,F。人越多,方法就越多。你就不想知道,谁的方法更好用?

所以,我积极组织与参加社群,要的就是与这些肯积极思考的人,一起想办法解决更多的问题,从而磨炼自己的思考方式。同时也让自己的错题本,越来越厚,越来越抗打。

于是,好玩的事情,层出不穷。就好比上面这个题,如果没有你们这些可爱水友的智慧,就不会讨论的那么深入。

一开始,大家想的方法,都很随意。简直就是在做入门的SQL题,直接update,merge, 甚至调用cursor. 给出这样方法的朋友,我猜大部分是刚入行的帅哥靓妹,还停留在正确使用SQL命令语法的阶段。

那么回答 update, merge, cursor 为什么不对呢?归根结底,还是对体系的掌握不够到位,缺乏对数据库日志,事务管理,存储引擎等的理解。

大量的数据更新,会造成对表的锁定,这样其他人就不能用表了。数据库的操作,会先记录日志,一个大事务,能将日志撑爆,然后整个数据库服务器就炸了。

试想,你家就一台电视机,世界杯上赛的时候,你老婆非霸占着看某凡的演唱会,你有多郁闷?!而且这场演唱会竟然耗时2个半小时,想死的心都有了,是不是?

更优化的方法,群里也讨论到了。我们可以批量跑,一次跑1万条或者5万条,在每次跑批结束时,稍加停顿,停1-2秒钟,然后继续下一轮。

嗯,听上去,很人性化。自己憋屈点,每次小批量的跑,不占用太多服务器资源,也不给日志文件带来短时间的膨胀,似乎已经为每个人,每类压力资源都考虑到了。

简直完美,那还有没有提高的空间呢?当然有。这里的缺点,也很显然,自己委屈了。7000万条数据,1万一次,跑7000次,每次就算1秒,加上停顿了1秒,这样就需要4个小时,才能处理完。

那实际跑下来,是不是能如期跑完呢,实际上,随着越来越多的数据被更新,维护的索引也会越来越复杂,越到后面,更新1万条数据就不再是1秒一次了。要等更新完数据,遥遥无期。

那做DBA的朋友,会怎么看待这个问题?

首先,肯定是表结构设计的问题。对于这类容易暴涨数据的表,设计前第一个事情,是做好分区管理。按照年,月,日去做分区,分区粒度把握好。分区的目的,可以提供多线程处理。这个特性很重要,分区是可以秒切的,无论多少数据,即使2亿数据,也就1秒。这样100个分区,切出100个小表来,用多线程处理完了,再切回来。

关于秒切分区,看这里:谈谈表分区

更新前, 先 checkpoint 完所有新鲜的日志,完成差异备份或日志备份。

预处理步骤完毕,接着把数据库备份模式改成simple模式,使其日志文件,可以循环利用。这样解决了日志暴涨带来的空间不够用的后顾之忧。接着丢弃其他暂时无用的表索引,只保留更新用到的条件判断索引。最后执行批量更新操作。

数据全部更新完毕之后,立即执行差异备份或日志备份,以保证其他更新都安全保存。重建其他索引,恢复数据库的Full模式。

至此,完成更新。

当然,代码怎么写呢,是不是简简单单像下面这样呢:

WHILE(True)
BEGIN 
    UDPATE TOP(10000) TAB_A 
        SET COL_A = 'XXX'
    WHERE COL_A IS NULL 
    
    WAIT FOR 1
    IF @@ROWCOUNT = 0 
        BREAK 
END 

@@ROWCOUNT代表上条语句影响的记录行数 本例用的是伪代码

我100%的告诉大家,肯定不是。这样的设计,逻辑是没错的,但程序是死的。不够灵活。假如服务器足够空闲,你会满意一次处理1万条吗。答案是,显然不会。这就体现你SQL功底了。

真正的功底,考察灵活而巧妙的设计,洞察你对业务世界的数据,抽象建模的能力

我一直认为,程序精妙处,在于迭代,在于你不断去反思,如何让你的程序跑得更好,更快,更稳。而大部分的程序员,仅仅满足于,把数据跑完,就拉倒。这样的10年经验,真的和一年没啥区别,无非你copy和paste的手速,会比其他人快点。

看到这里的同学,肯定被我吊足了胃口,那么正确答案是什么呢?抱歉,我不能给。

情景总是在不断的进化,每个特殊案例都有自己的特殊处理技巧,这世界没有银弹,一劳永逸地解决你将面临的所有问题。

解决眼前的问题,不要仅局限于一种方法。想出一个暂时的解决方法是急事,但拼命去想出,第二种,第三种方法是要事,以后能走多远,往往取决于要事,这些需要沉淀你思考的要事,才能给你更多力量。

--完--

往期精彩:

本号精华合集(三)

如何写好 5000 行的 SQL 代码

如何提高阅读 SQL 源代码的快感

我在面试数据库工程师候选人时,常问的一些题

零基础 SQL 数据库小白,从入门到精通的学习路线与书单

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dbLenis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值