文完本文转载自微信公众号《关于SQL》,作者Lenis。转载本文,有关SQL公众号请联系。周六清晨,东方刚刚露出白光。L早早来到办公室,还带着他最喜欢的热娇妈。今天将是一场硬仗。筹划两个月推出产品,今日正式发布。他需要非常敏捷的头脑。另外,只要L还在喝咖啡,就说明DB肯定没事,也能起到安抚大军的作用。所以在大型活动之前,L总是在星巴克附近闲逛。没有人能猜到他是喜欢喝酒还是炫耀自己的气味。F摇摇头走了过来。Release已经开始1个小时了,按理说DB部分的部署应该早就完成了。这一次略微超出了L的预料,但没有任何征兆,所以大家并没有太松口气。直到F来找L,低头问道:“L,有个更新数字的脚本,运行了四十多分钟还没结束,理论上只会更新一百万多条数据。这么久,不知道正常不?”F已经五岁了,该经历的都经历过了,现在出现这样的问题,L也是谨慎的。“哪段脚本?”SETNOCOUNTON;DECLARE@SalesQuotaKeyBigintDECLAREMY_CurCursorForSELECTTOP1000000SalesQuotaKeyFROMFactSalesQuotaAuditWHERESalesAmountQuota<500000ORDERBYSalesAmountQuotaASCOPENMY_CurFETCHNEXTFROMMY_CurINTO@SalesQuotaKeyWHILE(@@FETCH_STATUS=0)BEGINUPDATEFactSalesQuotaAuditSETSalesAmountQuota=SalesAmountQuota+100000WHERESalesQuotaKey=@SalesQuotaKeyFETCHNEXTFROMMY_CurINTO@SalesQuotaKeyENDCLOSEMY_CurDEALLOCATEMY_Cur“嗯,这段貌似会有问题,就看索引是怎么建的”Loftensaidthattroubleshootingislikebeingadetective.Sometimes,thewordsareactuallyforhimself,"IfyouaddanindextoSalesAmountQuota,itwillbedangerous.""Asexpected",LopenedtheSSMSwindowandfoundtheindex定义:CREATEUniqueCLUSTEREDindexPK_SalesQuotaKeyONFactSalesQuotaAudit(SalesQuotaKey)CREATEINDEXIDX_SALES_AMT_QUTAONFactSalesQuotaAudit(SalesAmountQuota)为保分析无误,L还是先看了下现状:SELECTTOP1000000SalesQuotaKeyFROMFactSalesQuotaAuditWHERESalesAmountQuota<500000ORDERBYSalesAmountQuotaASC“目前来看,这段脚本还在继续跑着”“但执行计划显示正确跑了SalesAmountQuota的Whatabouttheindex?"Fpuzzled,"Actually这真的是这个索引的错。”“使用了索引,但是每次更新,更新的行都落后于IDX_SALES_AMT_QUTA索引,导致SalesAmountQuota的值无限更新,直到大于500,000。”l认为过于强调seekIndexed,却没有对索引做全面透彻的解释,其实索引也有好心办坏事的时候,所以索引应该给F画个思维导图:》更新后数据返回给索引,游标一直读取满足条件的数据,你可以想想这个有趣的过程。”看到F频频点头,L觉得他解释清楚了。“终于结束了,”F看到监控Dashboard上的超长会话消失了,脸色开始愉悦起来。“大错即将发生。”L泼了一盆冷水,F不解,90后妹子的脸真像天气,瞬息万变。SELECTCOUNT(*)FROMFactSalesQuotaAuditWITH(NOLOCK)WHERESalesAmountQuota<500000"你看,结果是0,肯定不是你想要的结果。你的初衷肯定是那些低于50万的sales加10万,现在都加到50万。这是一个典型的万圣节问题。”“那么,我该怎么办?”F面对着让她脸红的游标,几乎要崩溃了。“用临时表,先更新数据,再求最优解。“什么?是万圣节问题吗?”故事发生在50年前的一个晚上。1970年前后,IBM的一群研究人员决定将年薪低于2.5万的员工的工资提高10%。他们写了一篇文章SQL的大意是:updateEmployeeSetSalary=Salary*(1+10%)whereSalary<25000结果运行完发现所有年薪低于25000的员工都会加到25000..他们的工资更新后,都达到了25000,这一天恰好是10月31日,万圣节,所以叫HalloweenProblem。
