索引重建进行到二十分钟时 VPN 掉线,SQL 客户端显示连接已断开,而那个最明显的问题在那条错误里没有答案。语句是跑完了、回滚了,还是在你不在的情况下继续运行?重连并重新提交是三个选项里最糟的,因为它把一个不确定的结果变成两个可能的结果。在下一个窗口到来之前,把这项工作交给一个有持久所有者的东西。

连接错误不会告诉你的事

客户端侧的报错描述的是客户端。它报告套接字已关闭,而不是服务器对事务做了什么。语句可能仍在执行,可能在链路中断前一刻就已提交,也可能在会话被清理时回滚了。这三种情况在你的笔记本上给出的是同一条消息。

只有服务器的状态才能给出结论。在做任何决定之前,先去那里看。

把工作交给服务器侧的所有者

对于不需要人盯着的工作,让数据库主机掌握执行权。SQL Server 代理按需或按计划运行作业,并记录每一次运行,因此作业的生命周期独立于你的 VPN 会话。作业身份只需要任务所要求的那部分权限,而不是管理员的完整交互上下文。这样笔记本只负责发起工作并读取结果,而不是成为让工作活下去的进程。

EXEC msdb.dbo.sp_start_job @job_name = N'nightly-customer-reindex';

代理是否可用取决于你部署的版本和服务。请使用你的平台实际提供的机制,而不要假设这一种到处都有。

靠近数据库的跳板机可以缩短路径,值得拥有,但它并不改变归属问题。网络一旦中断,会话仍然会结束。用它来观察,而不是用它来维持工作存活。

留下一条下一次会话能读到的记录

记录作业名称或标识符、目标数据库以及你期望的结果。正是这条记录,让另一个会话或另一个人能够回答那条错误无法回答的问题。没有它,你只剩一段模糊的更新记忆,无从核查。

EXEC msdb.dbo.sp_help_jobhistory @job_name = N'nightly-customer-reindex';

作业历史会显示每个步骤的结果和时间,这比一个成功标志更有用。对于会改动数据的任务,还要加上应用自身的校验:行数、校验和,或由作业写入的状态行。两条独立记录才能让重试变得安全,而记录下来的作业历史就是第一条。

重新提交前先核对

当用于观察的连接消失时,先找到已有的那次运行,再启动新的运行。阅读它的步骤结果,判断这项工作已提交、部分完成,还是从未开始。然后才按工作流定义的规则重试,因为盲目重提可能重复一次装载,或者第二次仍在半途失败。

保留持久的所有者和可核查的结果,一次短暂的访问故障就只是不便,而不是靠猜。这就是全部的设计目标:工作应当比请求它的那条连接活得更久。

相关文章