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


364

Чи є спосіб написати команду T-SQL, щоб просто спати протягом певного періоду часу? Я пишу веб-службу асинхронно і хочу, щоб я міг запустити деякі тести, щоб побачити, чи справді асинхронний візерунок зробить його більш масштабованим. Для того, щоб "знущатися над" зовнішньою службою, яка повільно, я хочу мати можливість зателефонувати на SQL-сервер зі скриптом, який працює повільно, але насправді не обробляє багато матеріалів.


19
Справедливе запитання! Можливо, я захочу використати це колись. Як цілий бік, це перший раз, коли я коли-небудь чув про те, щоб
хотіти, щоб база

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 секунд.

Ось функція Scalar-value, яка показує її використання; наведена нижче функція прийме цілий параметр секунд, який потім переводиться на 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

SQL Azure не подобається, що Only functions and some extended stored procedures can be executed from within a function. MS Docs подає приклад із використанням збережених програм - схоже, такий підхід недійсний
SliverNinja - MSFT

5

Ви також можете "WAITFOR" "TIME":

    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?
slartidan

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();
        }
      }
    }
  }
}

2
Якщо ви перебуваєте в c #, ви, ймовірно, повинні використовувати Thread.currentThread.sleep (60000) АБО Thread.sleep (60000), що робить те саме. Таким чином ваша затримка буде ізольована від вашої заявки. Потім зателефонуйте до подальшої логіки бази даних.
Дія

2
@ActionDan Використання Thread.Sleep не допоможе виконати CommandTimeout, чи не так? Як надуманий приклад, він робить те, що написано на коробці.
Річард Хауер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.