【问题标题】:Powershell run SQL job, delay, then run the next onePowershell 运行 SQL 作业,延迟,然后运行下一个
【发布时间】:2012-04-17 17:06:20
【问题描述】:

我正在编写一个 Powershell 脚本,它对本地 SQL Server 数据库执行多项操作。

我正在做的一件事是一个接一个地运行多个 SQL 作业。我这样运行它们:

 sqlcmd -S .\ -Q "EXECUTE msdb.dbo.sp_start_job @job_name = 'Rebuild Content Asset Relationship Data'"

有没有办法让 Powershell 延迟运行下一个作业,直到第一个作业完成?

谢谢

【问题讨论】:

  • 你的意思是延迟几秒?还是sqlcmd 不等到存储过程完成才退出?
  • 迈克:它不等待。一旦你执行命令,它会在 0.001 秒后返回:Job 'Rebuild Content Asset Relationship Data' started successfully.
  • 所以您的查询在技术上完成了,它只是在 SQL Server 中启动了一些后台进程。问题是 Powershell 究竟如何知道某个 SQL Server 进程何时完成?也许您可以每 x 秒轮询一次以检查它是否已完成?
  • 没错。它开始并最终完成。我如何以及每隔几秒轮询一次什么?这是最好的方法吗?我可以在 SQLcmd 中添加一个标志吗?
  • 一个快速的谷歌出现了这个:interworks.com/blogs/bbickell/2010/01/15/… - 也许将整个事情包装在一个启动工作的存储过程中,然后循环直到工作完成。然后从 Powershell 调用它..

标签: sql-server powershell


【解决方案1】:

要从 PowerShell 访问 SQL 代理作业,您可以使用 SMO:

编辑考虑到效率,如果您要将此功能添加到您的脚本中,我会将 SMO 加载出来并将其放置在您的脚本顶部附近(在此之前功能)。如果每次调用该函数时它都会重新加载程序集,它可能会减慢您的脚本。


Function Get-SQLJobStatus
{
    param ([string]$server, [string]$JobName)
    # Load SMO assembly, and if we're running SQL 2008 DLLs load the SMOExtended and SQLWMIManagement libraries
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null

    # Create object to connect to SQL Instance
    $srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server

    # used to allow piping of more than one job name to function
    if($JobName)
    {
        foreach($j in $jobName)
        {
            $srv.JobServer.Jobs | where {$_.Name -match $JobName} | Select Name, CurrentRunStatus
        }
    }
    else #display all jobs for the instance
    {
        $srv.JobServer.Jobs | Select Name, CurrentRunStatus
} #end of Get-SQLJobStatus
}

您可以使用此功能的方式示例:


#will display all jobs on the instance
Get-SQLJobStatus MyServer

#pipe in more than one job to get status
"myJob","myJob2" | foreach {Get-SQLJobStatus -Server MyServer -JobName $_}

#get status of one job
Get-SQLJobStatus -Server MyServer -JobName "MyJob"

你可以在你的脚本中使用这个函数,然后在一个 while 循环中反复调用它,直到你的工作状态显示为“空闲”。至少在我看来这是我认为可行的:)

【讨论】:

  • 它似乎有效,但我总是在所有工作中“闲置”。如果我使用原始帖子中的行从 powershell 运行作业......或者即使我从“Microsoft SQL server management Studio”运行作业......我仍然会为所有作业获得“空闲”。不知道该怎么办。我确保将服务器设置为“./”。我知道这很有效,因为如果我请求一份不存在的工作的状态,它不会给我任何东西。有什么想法吗?
  • 所以你是在调用作业开始然后用函数检查状态?如果您查看作业历史记录,作业运行需要多长时间?唯一可能有帮助的是检查上次运行日期是否大于当前时间。我不确定这是否适用于您的情况。
  • 暂时忽略我上面的评论......我想我还有更多工作要做......你的代码可能是可靠的。
  • 谢谢...我是个白痴...您的代码运行良好。问题是我在我的本地机器上用一个很快完成执行的小型 SQL 作业来测试它。当我在生产服务器上尝试使用需要 5 分钟才能完成的 SQL 作业时,我开始看到“空闲”更改为“执行”。谢谢!
【解决方案2】:

当然,在调用 sqlcmd.exe 之间执行 Start-Sleep -seconds <nn>

【讨论】:

  • 对不起,我应该指定我不想使用睡眠。其中一些作业需要 5 分钟才能运行。这个时间可能会因机器的速度而有很大差异。
【解决方案3】:

我的建议是将您的工作包装在一个新的存储过程中,该存储过程启动该工作,然后通过不断轮询其状态来等待它完成。从attached article,您可以执行以下操作:

DECLARE @JobStatus INT
SET @JobStatus = 0
EXEC MSDB.dbo.sp_start_job @Job_Name = 'JobName'
SELECT @JobStatus = current_execution_status  FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;', 
                          'EXEC MSDB.dbo.sp_help_job @job_name = ''JobName'', @job_aspect = ''JOB'' ')     
WHILE @JobStatus <> 4
BEGIN   
    SELECT @JobStatus = current_execution_status  FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;', 
                                'EXEC MSDB.dbo.sp_help_job @job_name = ''JobName'', @job_aspect = ''JOB'' ')    
END

然后,不要从命令行调用sp_start_job,而是从命令行调用您的存储过程,PowerShell 将被阻止,直到存储过程完成。希望这会有所帮助!

【讨论】:

    【解决方案4】:

    您的作业由 SQL Server 代理执行。要么直接从 PowerShell 脚本调用相应的存储过程(或 SQL 语句),要么在 here.

    中解释的行中实现某些内容

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-12
      • 2012-10-29
      • 2013-12-07
      • 1970-01-01
      • 2011-12-24
      相关资源
      最近更新 更多