Invoke-Sqlcmd在某些机器上大约30秒后超时,但在其他机器上不会(未指定 -QueryTimeout时)。默认超时值由什么决定,最佳实践是什么?
我在使用PowerShell的 Invoke-Sqlcmd 测试客户端超时:
Invoke-Sqlcmd -Query "WAITFOR DELAY '00:00:31'" `
-Database master `
-ServerInstance $env:COMPUTERNAME
Observed behavior:
- 在某些环境中,这会失败,错误信息如下:
Invoke-Sqlcmd:执行超时已过。完成操作的超时时间已到,或者服务器未响应。
(如果默认查询超时约为30秒,这很合理)
- 在其他环境中,即使我根本没有传入
-QueryTimeout,同样的命令也不会超时
问题
-
什么决定了
Invoke-Sqlcmd的默认查询超时?
为什么在某些机器上大约是30秒,而在不传入-QueryTimeout的情况下,在其他机器上却“没有限制”(或不同)? -
跨环境导致差异的典型原因有哪些?
-
生产脚本的最佳实践是什么?
解决方案
AlwaysLearning 在问题的评论中提供了关键线索:
你的症状表明,你的多台机器在使用 Invoke-SqlCmd cmdlet的不同版本,或可能在使用过时的版本:
有两种(从技术上讲是不同的)Invoke-SqlCmd cmdlets:[1]
(a) 过时的 [Invoke-SqlCmd] 命令,来自被废弃的 [SQLPS] 模块。
- 为了向后兼容,这个过时的模块仍随 SSMS 一起提供。
(b) 现行的 [Invoke-SqlCmd] 命令,来自后继模块 [SqlServer]
- 只有SSMS的 v16.x版本随该模块一起提供。
- 在v17.x及以上版本中,必须按需从 [PowerShell Gallery] 安装,例如:
Install-Module -Scope CurrentUser SqlServer
之后再升级,例如:Update-Module -Scope CurrentUser SqlServer
你可以在一个干净的会话中运行以下命令来判断一个机器上隐式加载的版本,并显示原始模块的版本号:
(Get-Command Invoke-SqlCmd).Module
注:如果在安装了现代 SqlServer 模块后,默认仍然加载到过时的 SqlPs 模块,请参阅此答案中的故障排除和卸载说明。
默认查询超时:
实现 (a) 在实际操作中似乎默认为 30 秒。
- 官方帮助主题,截止本稿撰写时,格式有误,缺少对
-QueryTimeout参数的描述(整体命令的描述被呈现为代替)。 -
要求性地说,关于该效应的权威说法不多,但以下来自 [Troubleshoot query time-out errors] 的指引:
-
如果查询在配置的超时值内(通常是30秒)没有返回任何数据
-
相比之下,实现 (b) 的默认行为是“不超时”,这是基于官方帮助主题对 -QueryTimeout 参数的描述:
-
如果未指定超时值,查询不会超时。
- 也许,较旧版本的
SqlServer模块也曾有30秒的超时;如果是这样,请升级到最新版,例如
Update-Module -Scope CurrentUser SqlServer
[1] 参见 [SQL Server PowerShell] 了解背景信息。