SQL Server数据迁移,不只是把数据搬过去

SQL Server数据迁移,不只是把数据搬过去

@toc

很多人一听 SQL Server 数据迁移,脑子里冒出来的第一个念头往往是:"迁完之后性能会不会变差啊?"这个担心其实特别实在。为什么呢?因为你要切换的数据库,往往都是在线上跑了好些年的老系统了。里头堆着历史数据呢,还有那种特别复杂的报表,定时的任务也是一堆。甚至有些业务习惯,压根就没写过什么设计文档。新的数据库能让你把数据导进去,这只能算干了一半的活儿。剩下的一半是什么呢?得等业务查询稳当了,报表能按时出数了,运维那边也能接得住了,这事儿才算完。

我个人的习惯呢,是把迁移当成给系统做一次全身体检。特别是在 BI 报表,还有那种要多表关联分析的场景里面。用户其实根本不关心你底层换成了什么数据库。用户只关心一点,那就是一个报表,从上面一直转圈"还在计算",变成一下子就能"直接查看"了。在 KES V9R4C019 的那次实测,给我留下了一个挺有代表性的印象。在那种带标量子查询的多表关联场景里头,100 个并发同时上的时候,复杂查询的 TPS 居然能往上提 60%。响应时间呢,直接给压到了原来的十分之一。不过大家得注意,这个数字是跟着特定的测试环境和特定的查询来的。你不能拿这个去套,觉得所有业务都能跑出这个结果。但它起码说明了一个问题,就是你搞国产数据库迁移,验收标准绝对不能仅仅只是"能跑起来"就完事了。

一、迁移前最该问的问题:业务到底慢在哪里

还没开始迁移呢,很多团队就先凑一块儿聊服务器怎么配了,CPU 给几核啊,存储用什么介质啊。其实业务上的问题还没搞明白呢。某个 BI 报表跑得慢,这是一个问题。那为什么会这样呢?原因可能有很多。是因为它扫的数据量实在太大了?还是说写的连接条件不太对?是因为统计口径算起来太复杂?还是说一并发起来,大家都在抢资源?又或者是数据库自己生成的执行计划不太稳?再或者是抽数据的那个链路本身就在那儿卡着?这些不同的原因,你对应的解决办法是完全不一样的。

通常来说,我会把慢查询归拢成三类来处理。第一类呢,就是单表或者就拉两三张表的明细查询。这种你重点盯什么呢?盯过滤条件写得对不对,索引有没有,还有它到底返回了多少行。第二类,是多表关联还要做聚合的。这种就得看它连接的顺序是怎么排的,统计信息准不准,数据有没有倾斜,还有中间跑出来的结果集有多大。第三类就是报表类的查询了。这种往往更烦人,里面经常夹杂着标量子查询啊,窗口函数啊,还有各种日期的计算,套了好几层。这种你就得盯着整个执行计划看了,还得看它并发的时候资源是怎么被吃掉的。

在迁移之前,你得留下一批真实的 SQL。千万别那种随便手写几个简单的例子来凑数。为什么呢?因为真实的 SQL 里面,往往藏着业务最常见的那些边界条件。而且它也能把兼容性上的那些差别给暴露出来。那你采集的时候要记些什么呢?SQL 的文本得记吧,参数的范围得记吧。还有返回了多少行,跑了多少时间,逻辑读是多少,物理读是多少,并发量有多大,当然还有执行计划。这些东西没有的话,你迁完之后说"感觉变快了"或者"感觉变慢了",这就太主观了,没法说理。 对于迁移项目的验收,我一般是拆成四条线来看的:

验收线 关注问题 典型证据
兼容性 对象、语法、事务语义是否一致 对象清单、失败 SQL、结果集对比
正确性 数据是否完整,报表口径是否变化 行数、抽样哈希、业务汇总
性能 并发下是否满足窗口和延迟 TPS、P95、资源曲线
可运维性 出问题能否发现、恢复和回退 告警、备份恢复、切换记录
flowchart LR A[SQL Server生产基线] --> B[对象与SQL分类] B --> C[样本迁移] C --> D[结果集校验] D --> E[单用户计划对比] E --> F[并发压测] F --> G{四条验收线通过?} G -- 否 --> H[调整映射/索引/SQL/资源隔离] H --> C G -- 是 --> I[灰度切换] I --> J[观察与回退窗口]

二、为什么复杂查询更能检验迁移质量

那种简简单单的 SELECT 语句,通常来说都不是什么难点。真正能考验数据库的,是那种多表关联、子查询、聚合,再加上并发,这些东西全堆在一块儿的时候。这时候就得看优化器了,看它能不能找到一条稳定的执行路径出来。

标量子查询就是一个很典型的例子。你光看它,觉得它不就是在主查询里面多补了一个字段嘛。但是呢,如果主查询一下子返回了几万行数据,那个子查询可能就会被重复执行几万次。这个计算成本一下就飙上去了。这还没完,如果再叠加上事实表、维度表还有明细表它们之间的关联。这个查询就绝对不是"多加一列"这么简单的事儿了。迁移之后的新数据库,如果说它能看懂你这个查询的结构,然后合理安排怎么连、怎么过滤。那它就有可能把中间结果集给降下来,把那些重复计算给砍掉。

下面这个呢,是我平时用来建 SQL Server 基线的一个简化写法。大家看的时候注意一下,这里的重点是记结果,而不是让你把这段代码原封不动地搬到目标库去跑。

sql 复制代码
SET STATISTICS IO ON;
SET STATISTICS TIME ON;

DECLARE @from datetime2 = DATEADD(day, -7, SYSUTCDATETIME());

SELECT o.customer_id,
       SUM(o.amount) AS total_amount,
       (SELECT MAX(p.paid_at)
          FROM payments p
         WHERE p.order_id = o.order_id) AS last_paid_at
FROM orders o
JOIN order_items i ON i.order_id = o.order_id
WHERE o.created_at >= @from
GROUP BY o.customer_id, o.order_id;

SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;

我呢,会把这条 SQL 的文本啊,参数啊,返回了多少行啊,还有逻辑读、CPU 时间以及执行计划,全都给存下来。接着呢,我会去目标环境的执行计划工具里头,再跑一遍同样的测试。这里要提醒一句,目标库的诊断命令还有它扩展的能力,你得按你实际用的版本来确认。你不能看它命令长得跟原来差不多,就直接照抄过来用,那是不行的。

不过话说回来,优化器它也不是什么魔法。如果表的统计信息过期了,或者索引选得不对,再或者参数分布变化特别大的时候。你换成什么数据库,它都有可能生成一个很烂的执行计划。所以说,我在看 KES V9R4C019 的性能到底怎么样的时候,我不会光看产品本身。我会把产品能力和工程操作这两件事搁在一块儿看。一方面呢,我看它在复杂查询上的执行能力到底怎么样。另一方面呢,我看做迁移的这个团队,有没有把统计信息给维护好,索引有没有整理,典型的 SQL 有没有去做调优。

三、SQL Server 数据迁移的实施步骤

第一步呢,得先把对象盘点清楚。除了那些表啊、视图啊、索引啊、存储过程啊这些常规的东西。你还得去盘一下作业、登录账号、权限,还有同义对象、外部的接口,甚至是报表工具的连接串。很多迁移搞砸了,其实并不是说数据没搬过去。而是因为某个夜间的作业,它还在傻乎乎地调着旧的连接串。又或者是报表平台那边,还在用着以前的老驱动。

第二步,就是做兼容性的分类。你可以把对象分成这么三类。第一类是直接就能兼容的,第二类是需要转一下的,第三类是需要重构的。直接兼容的,那就先迁过去接着做验证。需要转的,你得建一个明确的映射关系出来。需要重构的,那就别自己闷头搞了,得拉上业务和开发一块儿确认。这里有个大忌,就是你别把所有的问题都攒到切换前那一天再去解决。要不然的话,你那个迁移窗口就会变成一个压力极大的调试现场,谁也受不了。

第三步,搞一个样本库出来。这个样本库里面,结构得有代表性吧,数据量得有代表性吧,查询也得有代表性吧。如果是报表系统的话,你至少得把日常跑的报表、月末跑的报表、峰值时候的报表,还有临时让人写出来的分析 SQL 都给备齐了。弄这个样本库图什么呢?图的就是让你后面每一次做调整,都能有个东西拿来对比。而不是说你只跑了一次测试,就拍脑袋下结论了。

第四步,就是全量迁移加上增量同步了。全量那个阶段你盯紧点什么呢?盯字段映射对不对,字符集有没有问题,时间精度够不够,还有空值、主键和大字段这些容易出幺蛾子的地方。到了增量阶段呢,你的注意力就得转到日志位点上了。还有会不会来重复的数据,事件会不会乱序,失败了怎么重试。迁移工具的话,比如 KDMS,确实能帮你把对象转换啊、数据搬运啊、任务管理啊这些活儿给自动化了。但是工具吐出来的东西,你还是得拿去走业务校验,这步省不了。

第五步,上并发压测。单用户在那儿跑,感觉嗖嗖快,这根本说明不了什么问题。你得看 100 个并发砸上去的时候它还能不能稳住。测试的时候,你得尽量去模拟生产上读写比例是多少,报表访问的节奏是怎么样的。然后盯着 CPU、内存、存储的 I/O,还有锁等待和连接池的情况看。这个性能测试啊,你至少得跑个好几轮。别刚好有一次缓存全命中了,你就拿那个结果去说这就是它长期能力了,那是不对的。

第六步,也就是最后一步了,搞灰度切换。先别一上来就全量切。你先挑那种低风险的业务,或者干脆就是只读的报表来验一验。没问题了,再一点点把范围往外扩。在这个切换的过程里面,旧系统的回退条件你一定要给它留着。你得提前说好,谁来喊回退,回退的话会丢哪个时间段的数据,回退完了之后拿什么办法去补数据。你的迁移方案写得越细,真出问题的时候,大家就越不用去拼个人的经验。

一次压测应该记录什么

场景 并发 结果集行数 TPS/吞吐 P95 响应时间 备注
单用户冷缓存 1 实际记录 实际记录 实际记录 观察首次访问代价
单用户热缓存 1 实际记录 实际记录 实际记录 观察缓存命中影响
报表并发 100 实际记录 对比基线 对比基线 重点关注标量子查询
混合负载 按生产比例 实际记录 对比基线 对比基线 同时包含写入与查询

四、迁移后性能调优,我最关注四件事

第一个呢,就是统计信息。数据迁完了,目标库这边你得根据实际数据的分布情况,把统计信息给建起来。数据量多大啊,分布是怎么样的啊,增长的速度有多快啊,这些全都会影响执行计划。所以你不能偷懒,直接把旧系统那套维护周期照搬过来用。

第二个,看索引的质量。索引这东西,真不是越多就越好的。你加了一堆没用的索引,写入的时候成本就上去了,维护也费劲。但是如果你少了索引,那报表查起来就得全表扫,那更完蛋。所以你应该怎么搞呢?围着那些高频的过滤条件、连接条件、排序条件还有分组条件去调索引。调完之后呢,还得去执行计划里面看一眼,确认它是不是真的被用到了。

第三个,看 SQL 的结构。迁移的时候,没谁规定不让你改 SQL 的。遇到那种重复计算的啊,排了序但其实没用的啊,很早就把大字段给返回来了的啊,还有那种压根就没加范围限制的查询。只要你不把业务的语义给改了,你就可以去优化它。特别是那种标量子查询、套了好几层的嵌套,还有多表关联。你得拿不同的写法去跑一跑,比一比它们的执行计划和出来的结果集。

第四个,就是资源隔离。在线的交易啊,报表的查询啊,还有那种批量的任务,如果大家都在同一拨资源里面混着用。那就很容易互相打架,互相影响。怎么办呢?你可以搞读写分离啊,把连接池规划一下啊,给报表定个时段啊,或者让任务错开峰值跑。前面参考资料里头重点提的那个 KES 多集群架构,其实也是这个思路。就是通过不同的部署方式,去满足业务不能断啊、性能要能扩展啊,还有成本得控制住这些需求。

五、怎样客观看待"迁移后性能提升"

性能提升这事儿,它是有一个边界的。你换套硬件,或者数据量不一样了,SQL 写得不一样了,参数变了,并发模型也变了,那测出来的结果肯定不一样啊。对于你做项目来说,真正有意义的事情是什么呢?是把你自己的基线和验收条件给建起来。

我个人的建议是,你至少得设四类指标。第一类叫功能一致性,第二类叫性能达标,第三类叫稳定性,第四类叫运维可接管。功能一致性看什么呢?看数据量对不对,关键字段有没有丢,报表结果一不一致,还有事务的行为变没变。性能达标看什么呢?看核心 SQL 的 P95 响应时间达没达标,并发吞吐量够不够,批处理能不能在规定窗口里跑完。稳定性看什么呢?看它能不能连续跑不出错,出了故障能不能恢复,备份了能不能恢复回来。运维可接管看什么呢?看监控有没有,告警有没有,权限怎么分,审计怎么做,还有以后升级的流程通不通。

复杂查询的改写对照

标量子查询这东西,不是说你非得改它不可。但是呢,你很值得拿一个改写出来的版本去跟它做个对照。下面这种写法,就是先把每个订单最后一次支付的时间给聚合出来。接着呢,再回头去跟主查询连起来。这么搞,主要是为了方便你去比较。比较什么呢?比较那种重复执行的方式,和这种只聚合一次的方式,它们走出来的路径到底差在哪。

sql 复制代码
WITH last_payment AS (
    SELECT order_id, MAX(paid_at) AS last_paid_at
    FROM payments
    GROUP BY order_id
)
SELECT o.customer_id,
       SUM(o.amount) AS total_amount,
       lp.last_paid_at
FROM orders o
JOIN order_items i ON i.order_id = o.order_id
LEFT JOIN last_payment lp ON lp.order_id = o.order_id
WHERE o.created_at >= :from_time
GROUP BY o.customer_id, o.order_id, lp.last_paid_at;

这并不是说所有的查询都得照着这个改。它其实仅仅只是一种你可以拿去验证的调优办法。什么呢?就是你保证业务跑出来的结果是一模一样的,你只把里面那个可能重复计算的局部给换掉。然后呢,你再去分别测一下它们的执行计划、逻辑读还有并发时候的延迟情况。

你如果要去理解 KingbaseES 在迁移项目里面的优势,我觉得可以从几个方面来看。兼容性啊,迁移工具啊,集群的能力啊,还有复杂查询优化啊。它想干的事儿,不是简单地把原来的数据库名字换掉。它是想在你业务不中断的情况下,把迁移的阻力给降下来。而且呢,让你以后做运维、做性能治理的时候,能有一个更统一的基础。国产数据库想要真正进到核心业务里面去,靠的绝对不是那种搞一次宣传就喊"替代了"的做法。靠的是什么?靠的是一次又一次能验证的、能回退的、还能一直持续优化的这种工程实践。

所以说到底,做 SQL Server 数据迁移,最重要的一条经验其实就是一句话。数据搬过去,那仅仅只是一个动作而已。业务跑得稳不稳当,报表出得快不快,团队以后管不管得住,这些才是你要的结果。只要你把基线啊、验证啊、压测啊、回退啊这几件事给做扎实了。那这个迁移,它就不会变成一次赌运气的风险押注了。它反而可以变成一个机会,一个让你的系统性能和数据治理一起往上走的机会。

相关推荐
acd120092 小时前
Redis 缓存和数据库一致性,到底怎么搞?
数据库·redis·缓存
sugar__salt2 小时前
MyBatis-Plus 从入门到实战:高效简化数据库开发的完整指南
数据库·spring boot·mybatis·数据库开发
CodeBlog-star2 小时前
AI Agent 高并发实战:Redis 限流、队列、缓存与高可用全栈方案
数据库·redis·缓存
TDengine (老段)2 小时前
TDengine taosX 与 Explorer — 数据集成与可视化管理
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
Leon-Ning Liu3 小时前
Oracle 26ai新特性:Lock-Free Reservations(无锁预留)
数据库·oracle
xiaopai9453 小时前
WPS能否替代工程项目管理系统
大数据·数据库·项目管理系统·建米软件
数据库小学妹3 小时前
空间数据库查询慢怎么排查?索引失效、表膨胀、SQL优化实战(附排查命令)
数据库·性能优化·信创·故障排查·索引调优·空间数据库
Cloud云卷云舒3 小时前
从墨天轮排名中,分析近期增速快、中长期具备高潜力国产数据库
数据库·haishandb·工业云
lsylalalala3 小时前
mysql-索引1
数据库·mysql