Команда сна в T-SQL?

364

Есть ли способ написать команду T-SQL, чтобы просто заставить его спать в течение определенного периода времени? Я пишу веб-сервис асинхронно и хочу иметь возможность запускать некоторые тесты, чтобы увидеть, действительно ли асинхронный шаблон сделает его более масштабируемым. Чтобы «насмехаться» над внешней медленной службой, я хочу иметь возможность вызывать SQL-сервер со скриптом, который работает медленно, но на самом деле не обрабатывает тонны вещей.

SKB
источник
19
Честный вопрос! Я мог бы хотеть использовать это когда-нибудь. В целом, это первый раз, когда я слышал о том, чтобы БД работала медленнее;)
p.campbell
2
Я ошеломлен, вызывая асинхронный сервис из T-SQL.
Jmucchiello

Ответы:

616

Посмотрите на команду WAITFOR .

Например

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

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

Эта команда обеспечивает высокую степень точности, но она точна только в течение 10 мс - 16 мс на типичной машине, так как она зависит от GetTickCount . Так, например, вызов WAITFOR DELAY '00:00:00:001', скорее всего, вообще не будет ждать.

Сэм Шафран
источник
4
Кто-нибудь знает, как заставить это работать из функции? Я получаю (правильно, вероятно), но ради тестирования я хотел бы переопределить) 'Неправильное использование побочного эффекта оператора' WAITFOR 'внутри функции ....
monojohnny
2
@monojohnny, чтобы заставить SVF ждать, я попробовал ответ Джоша ниже, но это не сработало. Вместо этого я просто создаю цикл 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
GilesDMiddleton
3
Убедитесь, что вы используете 3 цифры для ms - «00: 00: 00: 01» не равно «00: 00: 00: 010», используйте вторую. (проверено на MSSQL 2016)
Ник
Вы также можете попробовать НАЧАТЬ СДЕЛКУ и ЗАВЕРШИТЬ СДЕЛКУ, если вам нужно заблокировать стол
Ричард Бальдауф
9
WAITFOR DELAY 'HH:MM:SS'

Я считаю, что максимальное время ожидания составляет 23 часа 59 минут 59 секунд.

Вот скалярная функция, чтобы показать ее использование; нижеприведенная функция примет целочисленный параметр в секундах, который затем преобразуется в ЧЧ: ММ: СС и выполняет его, используя 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
Джош Харрис
источник
SQL Azure не нравится этот Only functions and some extended stored procedures can be executed from within a function. MS Docs предоставляет пример с использованием Stored Procs - похоже, этот подход недопустим
SliverNinja - MSFT
5

Вы также можете «ОЖИДАТЬ» «ВРЕМЯ»:

    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
Джереми Джако
источник
2
Почему бы не использовать PRINTвместо RAISERROR?
Слартидан
4
Потому что иначе вы ничего не увидите, пока не закончится все ожидание. RAISERROR дает вам опцию NOWAIT, поэтому он покажет вам операторы печати (в основном) в реальном времени, а не когда буфер заполнен или после завершения пакета.
Джереми Джако
0

Вот очень простой фрагмент кода на 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();
        }
      }
    }
  }
}
user2192239
источник
2
Если вы находитесь в c #, вам, вероятно, следует использовать Thread.currentThread.sleep (60000) ИЛИ Thread.sleep (60000), который делает то же самое. Таким образом, ваша задержка изолируется от вашего приложения. Затем вызовите вашу последующую логику базы данных.
Действие Дан
2
@ActionDan Использование Thread.Sleep не поможет в использовании CommandTimeout, правда. В качестве надуманного примера он делает то, что написано на коробке.
Ричард Хауэр