【发布时间】:2013-05-02 15:14:45
【问题描述】:
我有一个奇怪的问题,大约只发生 100 次。我有一个使用 SQL 的 SMO 库进行数据库备份的 PowerShell 脚本。这是我用来解决问题的相关代码的片段:
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | out-null
$now = get-date
########################################
$server = new-object Microsoft.SqlServer.Management.Smo.Server
$server.ConnectionContext.StatementTimeout = 86400 # Allow backups to take up to 24 hours per database
$databases = $server.Databases
$script:totalsteps = $databases.count
########################################
if($script:totalsteps -eq $null -or $script:totalsteps -eq 0) {
$body = "Backup start:" + $now.tostring("yyyy-MM-dd hh:mm:ss tt") + "`r`n" +
"Error: " + (get-date).tostring("yyyy-MM-dd hh:mm:ss tt") + "`r`n" +
"`$script:totalsteps: " + $script:totalsteps + "`r`n" +
"`$databases.count: " + $databases.count + "`r`n" +
"`$databases: " + $databases + "`r`n" +
"`$server: " + $server
send-mailmessage -from "me@example.com" -to "me@example.com" -subject "Server Null: $server" -smtpserver "mail.example.com" -body $body
}
问题是有时 if 语句被评估为真,我收到一封电子邮件,如下所示:
Backup start: 2013-04-30 07:50:58 AM
Error: 2013-04-30 08:02:19 AM
$script:totalsteps:
$databases.count: 4
$databases: [master] [model] [msdb] [tempdb]
$server: [serverA]
值得注意的是,脚本启动时间与错误时间大约为 11 分钟,这有点奇怪。我现在唯一的猜测是服务器承受着很大的压力,因此 PowerShell 默默地失败了变量分配并继续前进。
100 次 if 语句中有 99 次是错误的,我没有收到电子邮件。我不明白为什么$script:totalsteps 分配不是 100% 的时间。有任何想法吗?我还能做些什么来解决这个问题?
更新
为了测试惰性求值理论,我把代码改成了:
System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | out-null
$now = get-date
########################################
$server = new-object Microsoft.SqlServer.Management.Smo.Server
$server.ConnectionContext.StatementTimeout = 86400 # Allow backups to take up to 24 hours per database
$databases = $server.Databases
$script:totalsteps = $databases.count
############ NEW NEW NEW NEW ###########
if($script:totalsteps -eq $null -or $script:totalsteps -eq 0)
{
$script:totalsteps = $databases.count * 4
send-mailmessage -from "me@example.com" -to "me@example.com" -subject "Server Null: $server" -smtpserver "mail.example.com" -body "FIRST ATTEMPT"
}
########################################
if($script:totalsteps -eq $null -or $script:totalsteps -eq 0)
{
$body = "Backup start:" + $now.tostring("yyyy-MM-dd hh:mm:ss tt") + "`r`n" +
"Error: " + (get-date).tostring("yyyy-MM-dd hh:mm:ss tt") + "`r`n" +
"`$script:totalsteps: " + $script:totalsteps + "`r`n" +
"`$databases.count: " + $databases.count + "`r`n" +
"`$databases: " + $databases + "`r`n" +
"`$server: " + $server
send-mailmessage -from "me@example.com" -to "me@example.com" -subject "Server Null: $server" -smtpserver "mail.example.com" -body $body
}
【问题讨论】:
-
只是在这里猜测,但由于赋值是对
$databases变量的第一次访问。我相信对这些的评估是懒惰的,所以当它尝试枚举数据库时你可能会超时因为它首先需要打开一个连接。之后,您已经获取了数据,因此在您第二次使用时可以使用它。不过有点难以验证。 -
我建议您也将
$Error变量与您的电子邮件一起发送,它实际上可能包含原因 -
好主意。一位同事建议在作业和 if 语句之间添加一个睡眠,所以我已经这样做了。我还在电子邮件中添加了 $error 变量。我敢打赌,您对第一次延迟评估超时是正确的。我可能会尝试在 if 语句中重新分配变量,看看是否可以修复它。但是,在我查看我刚刚所做的更改是否有用之后,我会尝试这样做。我会在一两天内更新。
-
这比预期的要快。睡眠没有效果,$error 变量在电子邮件中显示为 $null。我已更新帖子以使用您的第一个建议。
-
看起来编辑正在解决问题。我对其进行了调整,以便在两个 if 语句中都向我发送电子邮件。我只收到来自第一个 if 语句的电子邮件。所以有时变量赋值会失败(可能是由于惰性评估),但随后它被 if 语句捕获并修复。随意发布一些我可以接受的东西作为答案。
标签: sql powershell