尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SQL Server数据迁移实战——把一张慢报表拆开测

SQL Server数据迁移实战——把一张慢报表拆开测 文章目录把“慢”拆成四个问题先保存一份可重复的基线标量子查询为什么值得单独拿出来迁移不只是对象转换用验收指标替代“感觉快了”迁移后的第一周我会盯住什么别忽略连接层和时间语义索引和统计信息要在真实数据上复查前阵子开了一个 SQL Server数据迁移的评审会。当时业务那边的一个同事就问了我一句“迁移完之后这张报表能不能在十秒里面打开”其实我当时没直接说行或者不行。为什么呢因为同一张报表啊它碰上不同的参数还有不同的缓存情况加上不同的并发量这背后跑的可能完全是三条不同的 SQL。你直接给人家打包票这其实比承认你要去测一下要危险得多。后来我就把这事弄成一个小实验了。先把慢报表给拆开拆成几个可以单独测的查询。接着再挨个看扫描的情况、关联的情况、标量子查询的情况还有就是并发的时候有没有资源争抢。把“慢”拆成四个问题一张 BI 报表打开很慢的话其实往往是下面这四类问题搅和在一起了我一般会先画一条线。就是把数据从源库到报表的路径给画出来。迁移团队经常干的一件事就是仅仅只是把数据库给替换了。但是报表工具、连接池还有那些定时跑的抽取任务他们经常给漏掉。最后你看到的那个所谓的“数据库性能问题”其实它发生在链路的另外一头。SQL Server源库报表SQL/存储过程BI连接池报表页面夜间抽取任务报表中间表KingbaseES目标库兼容/转换后的SQL目标连接池同一报表验收先保存一份可重复的基线基线这个东西啊其实不等于你把 SQL 复制粘贴到文档里就完事了。你至少得把参数的范围、结果集到底有多少行、跑了多少时间、CPU 的情况、逻辑读还有物理读的情况再加上执行计划这些都一起存下来。下面这个是 SQL Server 这边的一个简单版的采集模板SETNOCOUNTON;SETSTATISTICSIOON;SETSTATISTICSTIMEON;DECLAREfrom_timedatetime2DATEADD(day,-7,SYSUTCDATETIME());DECLAREtenant_idint12;SELECTo.tenant_id,o.customer_id,SUM(i.quantity*i.unit_price)ASamount,(SELECTMAX(p.paid_at)FROMpaymentsASpWHEREp.order_ido.order_id)ASlast_paid_atFROMordersASoJOINorder_itemsASiONi.order_ido.order_idWHEREo.tenant_idtenant_idANDo.created_atfrom_timeGROUPBYo.tenant_id,o.customer_id,o.order_id;SETSTATISTICSTIMEOFF;SETSTATISTICSIOOFF;你就光跑三次其实是不够的。我通常来说会做三组测试。一组是冷缓存一组是热缓存还有一组是带并发的。然后把输出的东西整理成下面这个表测试组并发缓存状态结果集行数CPU/读P95目的A1冷实测实测实测看首次读取成本B1热实测实测实测看计划和缓存命中C100混合实测实测实测看复杂查询并发能力D按生产比例混合实测实测实测看交易和报表互相影响这样干有个什么好处呢就是迁移完你说它“变快了”这个是可以解释得清楚的。到底是扫描变少了呢还是说缓存刚好变好了或者是连接池的配置不一样了又或者是数据库的执行计划给换掉了如果没有这一层的拆解那性能对比往往就变成了纯纯的宣传数字了。标量子查询为什么值得单独拿出来标量子查询这个写法呢其实是很直白的。就是主查询先拿出来一行订单然后再去查一次支付表把最后的支付时间给补上。但是订单数量要是很多的话这个子查询可能就会被重复执行很多很多次。目标数据库到底能不能优化它统计信息准不准支付表上面有没有合适的索引这些其实都会影响最后的结果。我会把它改成“先做聚合然后再回去关联”的这样一个版本。拿这两个版本去做 A/B 测试WITHlast_paymentAS(SELECTorder_id,MAX(paid_at)ASlast_paid_atFROMpaymentsGROUPBYorder_id),order_amountAS(SELECTo.order_id,o.tenant_id,o.customer_id,SUM(i.quantity*i.unit_price)ASamountFROMordersASoJOINorder_itemsASiONi.order_ido.order_idWHEREo.tenant_id:tenant_idANDo.created_at:from_timeGROUPBYo.order_id,o.tenant_id,o.customer_id)SELECTa.tenant_id,a.customer_id,a.amount,p.last_paid_atFROMorder_amountASaLEFTJOINlast_paymentASpONp.order_ida.order_id;这里呢并没有一个“改写完就一定快”的结论。我要去验证的东西是这几点。这两种 SQL 跑出来的结果是不是一致的中间结果是不是变少了执行计划能不能稳住100 并发的时候 P95 有没有变好如果说改写之后的版本在数据量比较小的那些租户上面反而更慢了那我也得记下来。为什么呢因为这说明了优化方案得看数据分布来选。迁移不只是对象转换SQL Server 做数据迁移的话你至少得去盘点五类对象。也就是表和索引、视图和存储过程、作业和调度、账号和权限还有 BI 工具跟外部接口。KDMS 这类的迁移工具它确实能帮你把对象转换、任务编排还有数据搬运的效率提上去。但是呢它没法替业务人员去确认“这张报表算出来的口径到底对不对”这件事。否是对象盘点语法/类型/权限分类小样本迁移结果集对比单用户计划对比100并发压测性能与正确性均通过?改索引/SQL/连接池/资源隔离灰度切换保留回退窗口我一般会给对象做下面这种分类。而不是一碰到迁移失败就统统叫作“兼容性问题”分类例子处理方式直接兼容普通表、基础查询、常用约束自动转换后验证需要调整类型映射、分页、日期函数、存储过程建映射表并做回归需要重构依赖外部服务的作业、特殊扩展、隐式权限业务与开发共同确认需要替代目标平台不存在的专有能力先定替代方案再迁数据用验收指标替代“感觉快了”资料里面给的那个特定测试结果是这样说的100 并发下面复杂查询的 TPS 提升了 60%响应时间是迁移前的十分之一。那我会在项目的验收单里面这样去写测试对象含标量子查询的多表关联报表 并发模型100 个并发请求参数分布来自生产脱敏样本 对比版本源环境基线 vs KES V9R4C019目标环境 记录指标TPS、P50/P95、CPU、逻辑读、物理读、错误率 结论口径只对本测试数据、SQL、硬件和参数组合负责实际项目里面呢其实还要补上四项验收验收线必须回答的问题正确性行数、金额、时间边界和报表口径是否一致性能P95 和并发吞吐是否达到项目基线稳定性连续运行、备份恢复、节点故障是否可控可接管运维能否监控、告警、定位和回退那么说到 KingbaseES 在这类迁移里面的价值我觉得应该从几个方面一起来看。也就是兼容性、迁移工具、集群架构还有复杂查询优化这几个点。它并不是说把数据库名字换一下就拉倒了。而是说让迁移之后的业务有机会在同一套架构里面继续去搞性能治理。对于 BI 用户来说最后要的结果其实很直接。就是报表能按时打开算出来的数字跟以前一样出了问题的话得有人能找到原因在哪儿。这次实验其实让我确认了一件事。就是说 SQL Server 数据迁移里面最有效的技术动作其实不是先去讨论什么“国产数据库快不快”。而是你得先把一张慢报表给拆开拆成可以重复去测量的对象。数据也好计划也好并发也好权限还有回退这些都能被记录下来。那么迁移这件事就从喊口号式的替换变成了一个可以复现的工程过程。迁移后的第一周我会盯住什么很多性能上的问题啊其实并不会在你压测的那天冒出来。为什么呢因为压测的数据往往比较干净。连接池也是刚启动的统计信息也是刚刚更新过的。但是生产环境里面有什么呢有月末的报表、定时的任务、很长的事务、补录的数据还有不同部门同时在查。切换之后的第一周我会把“到底能不能用”这件事给拆成每天要检查的条目。而不是光盯着一个平均响应时间看。首先呢我会看查询的分布有没有发生变化。迁移之前你收集的那些 Top SQL可能仅仅只是覆盖了常规的工作日。切换之后呢你得去观察一下。是不是冒出来一些新的高频查询是不是有报表工具自己生成的 SQL又或者是某个接口在那里不停地重试其次的话得看计划是不是漂移了。同一条 SQL 在参数差很多的时候它可能走完全不同的计划。所以你不能只存一份“看着正常”的计划截图就完事了。第三点看资源隔离到底有没有效。在线的交易、夜间的批处理还有 BI 查询如果都在同一个资源池里面抢东西的话那你单条 SQL 优化得再好可能也解决不了系统级别的等待。我会去建一个很朴素的日报。里面就是核心接口的错误率、P50/P95、并发的连接数、等待事件、磁盘队列、最长的事务、备份的状态还有增量任务的延迟。弄这个日报其实不是为了造出更多的表格来。而是为了让性能问题能有一个时间线。打个比方P95 如果从周二下午开始变差了那刚好对应的是一个新报表上了线或者是统计信息维护失败了。这样的话你排查的范围就会小很多。对于那些算金额的、算库存的、算考勤的这种口径很敏感的 BI 报表我会把“结果集一致”这件事情做成自动对账。怎么对呢不是让你去拿两份 Excel 整个去比。而是按照业务日期、租户、组织还有指标先做汇总比对。然后再把有差异的分组下钻到明细里面去看。如果只是跑得快但是口径算错了那迁移还是失败的。反过来也一样口径是对了但是用户要等半天那也不能算完事。正确性和性能这两件事必须得同时去验收。最后要说一下回退策略。回退这件事啊它不是一句“出问题了我们就切回去”这么简单的。它需要你回答几个问题。回退之前目标库里面到底已经写进去了什么东西这些写进去的东西怎么回放到旧系统里面双写允不允许回退的判断到底由谁来做你把这些细节提前给写清楚了团队才不会在压力最大的时候去临时讨论数据会不会丢的问题。别忽略连接层和时间语义SQL 都改完之后呢我还会去检查连接层这一块。报表工具的连接池上限是多少空闲连接怎么回收超时怎么设置的重试的策略是什么这些其实都会把数据库的问题给放大或者给掩盖掉。一个超时设置得太短了可能就会把慢查询变成一场重试风暴。那连接池要是设置得太大了呢又可能让并发把数据库直接给压满了。迁移的时候源环境的参数你得留着做对比。但是呢不能死板地去复制。因为目标集群的资源情况还有并发的模型可能跟原来是不一样的。时间字段这个东西呢也值得单独拿出来做一下回归。历史系统里面你经常能看到本地时间、UTC 时间、字符串格式的日期还有月底的边界这些东西混在一起用。报表在按天或者按月去统计的时候时区怎么转有没有夏令时零点的边界怎么算遇到空的日期怎么处理这些都会影响到金额或者数量。我的做法是去挑四类样本。就是月末的数据、年末的数据、跨时区的数据还有补录的数据。然后跟业务人员一起去看结果。而不是光抽一段普通工作日的数据就看完了。还有就是权限的问题。迁移完之后账号能连上数据库这并不代表权限的语义就完全一致了。只读的报表账号、跑批处理的账号、运维的账号还有应用的账号这些应该分开去验证。特别要确认一下视图、存储过程还有数据导出会不会出现越权的情况。性能和安全看起来好像是两码事。但是一次搞错了的权限回退也有可能让应用跑到它不该跑的查询路径上去。索引和统计信息要在真实数据上复查迁移全都弄完之后呢我不会把源库里面的所有索引一个不差地给复制过来。因为有些索引在旧系统里面它其实就是历史遗留的已经没有查询在用它了。还有些索引呢到了目标库的执行计划下面你可能得去调整列的顺序。另外还有一些索引它虽然能让报表跑得快一点但是却会把高频的写入给明显拖慢。比较稳当的一个做法是先把主键、唯一约束还有核心查询用到的索引给留着。然后再根据真实的工作负载一步一步地去补。统计信息这个东也不能光在全量导入完的时候更新那么一次就不管了。你做数据导入、跑增量同步还有业务切换这些都会把数据的分布给改掉。特别是那些按租户、按日期或者按状态去过滤的表。对于高频的报表我会把统计信息更新的时间、参数的分布还有计划的变化都给记下来。一旦性能出现波动了我先去确认的是基数估计是不是偏离了。而不是说第一时间跑去强制走某一个执行计划。这样做的话确实会慢一点。但是它能让后续的治理有数据的依据在那儿摆着。
返回列表