Invoke-Sqlcmd 未指定 -QueryTimeout 时默认多久超时?
结论
Invoke-Sqlcmd 的默认超时行为取决于运行环境。当前 SqlServer 模块文档说明,省略 -QueryTimeout 后,查询不会受该参数的时间限制;底层 SqlCommand.CommandTimeout 的默认值则是 30 秒。因此,如果某些环境在约 30 秒后超时,而另一些环境没有超时,应先确认实际运行的 Invoke-Sqlcmd 实现、模块版本和调用方式。SqlServer 模块文档;SqlCommand.CommandTimeout 文档
题目中的测试使用 WAITFOR DELAY '00:00:31' 延迟 31 秒,适合用来区分 30 秒超时和无超时的行为。出现 Execution Timeout Expired,说明客户端命令执行遇到了超时;错误本身无法说明超时值由 SQL Server 设定,也无法确定具体是哪个 PowerShell 模块设定了该值。
为什么不同机器的表现不同
排查时可以先确认机器实际加载的命令来源和版本。机器上可能同时安装旧的 SQLPS 和较新的 SqlServer 模块,也可能装有多个模块版本。同名命令还可能被函数、脚本或其他模块遮蔽。不同实现的默认处理方式可能不同,脚本包装层也可能显式传入超时值,或分别限制连接和命令的等待时间。
在与实际脚本相同的 PowerShell 会话中运行:
Get-Command -All Invoke-Sqlcmd |
Select-Object Name, CommandType, Source, Version, Definition
Get-Module SqlServer, SQLPS -ListAvailable |
Select-Object Name, Version, Path
Get-Command -All 会显示可解析到的同名命令,Get-Module -ListAvailable 会列出已安装模块及其路径。还应检查脚本是否调用了包装函数、是否通过变量传入 -QueryTimeout,以及是否使用连接字符串或其他数据访问代码执行查询。当前 SqlServer 文档说明,省略 -QueryTimeout 后,查询不会因该参数而超时。底层 SqlCommand 的 30 秒默认值不能直接视为所有 Invoke-Sqlcmd 版本的默认值。SqlServer 模块文档
-ConnectionTimeout 和 -QueryTimeout 分别控制连接和查询执行阶段。前者限制建立数据库连接的等待时间,后者限制查询执行时间。连接成功后仍在约 30 秒时出现 Execution Timeout Expired,应检查查询超时设置和实际执行实现。
生产脚本的设置方式
生产脚本应显式设置 -QueryTimeout,根据查询的合理运行时长、业务 SLA 和任务调度窗口选择有限的超时值,以免依赖机器上的隐式默认值。下面的 120 秒仅为示意,应根据具体作业调整:
Invoke-Sqlcmd `
-Query "EXEC dbo.RunReport" `
-Database master `
-ServerInstance $env:COMPUTERNAME `
-QueryTimeout 120 `
-ConnectionTimeout 15 `
-ErrorAction Stop
如果查询确实需要不设命令超时,当前文档所述的 SqlServer 模块允许省略 -QueryTimeout;支持该参数的实现通常也以 -QueryTimeout 0 表示不限制时间。无限等待可能让进程、连接和调度资源长期被占用。只有确认运行环境和命令实现,并为任务配置了独立的监控和取消机制后,才应采用无限等待。当前文档列出的 -QueryTimeout 有效值为 1 到 65535;如果要使用 0,应先核对目标模块版本的行为。Invoke-Sqlcmd 参数说明
注意事项
查询超时限制的是客户端等待命令完成的时间,SQL Server 端的工作不一定会在同一时刻停止。发生超时后,应确认调用端的取消行为、服务器端会话状态和作业重试策略,再决定是否重试。对于有副作用的写入操作,重试前还要评估重复执行的风险。-ConnectionTimeout 控制的是连接建立时间;某台机器上观察到的默认值也不一定适用于其他环境。
备注:内容仅供参考。
