【问题标题】:Sleep Command in T-SQL?T-SQL 中的睡眠命令?
【发布时间】:2010-10-14 11:23:28
【问题描述】:

有没有办法写一个 T-SQL 命令让它休眠一段时间?我正在异步编写 Web 服务,我希望能够运行一些测试以查看异步模式是否真的会使其更具可扩展性。为了“模拟”缓慢的外部服务,我希望能够使用运行缓慢但实际上并没有处理大量内容的脚本调用 SQL 服务器。

【问题讨论】:

  • 公平的问题!我可能想在某个时候使用它。顺便说一句,这是我第一次听说希望数据库变慢;)
  • 从 T-SQL 调用异步服务让我感到困惑。

标签: sql-server tsql asynchronous sleep


【解决方案1】:

查看WAITFOR 命令。

例如

-- wait for 1 minute
WAITFOR DELAY '00:01'

-- wait for 1 second
WAITFOR DELAY '00:00:01'

此命令可让您获得高精度,但在典型机器上是only accurate within 10ms - 16ms,因为它依赖于GetTickCount。因此,例如,调用WAITFOR DELAY '00:00:00:001' 可能根本不需要等待。

【讨论】:

  • 有谁知道如何让这个函数从函数中工作?我得到(可能正确),但为了测试,我想覆盖)'在函数中无效使用副作用运算符'WAITFOR'......
  • @monojohnny 让 SVF 等待,我在下面尝试了 Josh 的答案,但它没有用。相反,我只是创建一个像这样的 WHILE 循环:CREATE FUNCTION [dbo].[ForcedTimeout](@seconds int) returns int as BEGIN DECLARE @endTime datetime2(0) = DATEADD(SECOND, @seconds, GETDATE()); WHILE (GETDATE() < @endTime ) BEGIN SET @endTime = @endTime; -- do nothing, but SQL requires a statement. END
  • 确保使用 3 位 ms - '00:00:00:01' 不等于 '00:00:00:010' 使用第二个。 (在 MSSQL 2016 上测试)
  • 如果你需要阻塞一个表,你也可以尝试 BEGIN TRANSACTION 和 END TRANSACTION
  • '00:00:00:001' 正确吗?链接的文档指出格式为hh:mm[[:ss].mss],带有句点,而此答案使用冒号。
【解决方案2】:
WAITFOR DELAY 'HH:MM:SS'

我相信这可以等待的最长时间是 23 小时 59 分 59 秒。

这是一个标量值函数来展示它的用途;下面的函数将采用一个以秒为单位的整数参数,然后将其转换为 HH:MM:SS 并使用EXEC sp_executesql @sqlcode 命令进行查询。下面的函数仅用于演示,我知道它不适合用作标量值函数! :-)

    CREATE FUNCTION [dbo].[ufn_DelayFor_MaxTimeIs24Hours]
    (
    @sec int
    )
    RETURNS
    nvarchar(4)
    AS
    BEGIN


    declare @hours int = @sec / 60 / 60
    declare @mins int = (@sec / 60) - (@hours * 60)
    declare @secs int = (@sec - ((@hours * 60) * 60)) - (@mins * 60)


    IF @hours > 23 
    BEGIN
    select @hours = 23
    select @mins = 59
    select @secs = 59
    -- 'maximum wait time is 23 hours, 59 minutes and 59 seconds.'
    END


    declare @sql nvarchar(24) = 'WAITFOR DELAY '+char(39)+cast(@hours as nvarchar(2))+':'+CAST(@mins as nvarchar(2))+':'+CAST(@secs as nvarchar(2))+char(39)


    exec sp_executesql @sql

    return ''
    END

如果您希望延迟超过 24 小时,我建议您使用 @Days 参数持续数天并将可执行的函数包装在循环中...例如..

    Declare @Days int = 5
    Declare @CurrentDay int = 1

    WHILE @CurrentDay <= @Days
    BEGIN

    --24 hours, function will run for 23 hours, 59 minutes, 59 seconds per run.
    [ufn_DelayFor_MaxTimeIs24Hours] 86400

    SELECT @CurrentDay = @CurrentDay + 1
    END

【讨论】:

【解决方案3】:

您也可以“等待”一个“时间”:

    RAISERROR('Im about to wait for a certain time...', 0, 1) WITH NOWAIT
    WAITFOR TIME '16:43:30.000'
    RAISERROR('I waited!', 0, 1) WITH NOWAIT

【讨论】:

  • 为什么不用PRINT 而不是RAISERROR
  • 因为否则在整个等待完成之前您什么都看不到。 RAISERROR 为您提供了 NOWAIT 选项,因此它将(基本上)实时显示打印语句,而不是在缓冲区已满或批处理完成后显示。
【解决方案4】:

这是一段非常简单的 C# 代码,用于测试 CommandTimeout。 它会创建一个等待 2 秒的新命令。 将 CommandTimeout 设置为 1 秒,运行时会看到异常。 将 CommandTimeout 设置为 0 或高于 2 的值将运行良好。 顺便说一句,默认的 CommandTimeout 是 30 秒。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Data.SqlClient;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var builder = new SqlConnectionStringBuilder();
      builder.DataSource = "localhost";
      builder.IntegratedSecurity = true;
      builder.InitialCatalog = "master";

      var connectionString = builder.ConnectionString;

      using (var connection = new SqlConnection(connectionString))
      {
        connection.Open();

        using (var command = connection.CreateCommand())
        {
          command.CommandText = "WAITFOR DELAY '00:00:02'";
          command.CommandTimeout = 1;

          command.ExecuteNonQuery();
        }
      }
    }
  }
}

【讨论】:

  • 如果你在 c# 中,你可能应该使用 Thread.currentThread.sleep(60000) 或 Thread.sleep(60000) 来做同样的事情。这样,您的延迟就与您的应用程序隔离开来。然后调用你后续的数据库逻辑。
  • @ActionDan 使用 Thread.Sleep 并不能帮助锻炼 CommandTimeout,不是吗。作为一个人为的例子,它会按照盒子上写的内容进行操作。
猜你喜欢
  • 2023-03-09
  • 2015-09-23
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 2014-07-13
  • 1970-01-01
  • 2018-02-20
相关资源
最近更新 更多