2009-03-20 4 views
309

Czy istnieje sposób, aby napisać polecenie T-SQL, aby po prostu spać przez pewien okres czasu? Piszę usługę internetową asynchronicznie i chcę mieć możliwość uruchomienia niektórych testów, aby przekonać się, czy asynchroniczny wzorzec rzeczywiście zwiększy skalowalność. Aby "pozorować" zewnętrzną usługę, która jest wolna, chcę mieć możliwość wywoływania serwera SQL za pomocą skryptu działającego powoli, ale w rzeczywistości nie przetwarzającego wielu rzeczy.Polecenie uśpienia w T-SQL?

+15

Fair pytanie! Może kiedyś z tego skorzystam. Na marginesie, po raz pierwszy słyszałem o tym, że chcę, żeby DB działał wolniej;) –

+2

Jestem zdumiony, wywołując usługę asynchroniczną z T-SQL. – jmucchiello

Odpowiedz

511

spojrzenie na rozkaz WAITFOR

Eg.

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

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

Komenda ta pozwala na wysoki stopień precyzji, ale jest only accurate within 10ms - 16ms na typowym komputerze, gdyż opiera się na GetTickCount. Na przykład wywołanie WAITFOR DELAY '00:00:00:001' prawdopodobnie nie spowoduje żadnego oczekiwania.

+2

Ktoś wie, jak uruchomić to z funkcji? Dostaję (poprawnie prawdopodobnie), ale ze względu na testy chciałbym przesłonić) "Niepoprawne użycie operatora powodującego efekt uboczny 'WAITFOR' w funkcji .... – monojohnny

+1

@monojohnny, aby SVF czekać, ja ' próbowałem odpowiedzi Josha poniżej, ale to nie zadziałało. Zamiast tego po prostu tworzę pętlę WHILE w następujący sposób: 'CREATE FUNCTION [dbo]. [ForcedTimeout] (@ seconds int) zwraca int jako BEGIN DECLARE @endTime datetime2 (0) = DATEADD (SECOND, @seconds, GETDATE()) ; WHILE (GETDATE() <@endTime) BEGIN \t SET @endTime = @endTime; - nic nie rób, ale SQL wymaga instrukcji. END' – GilesDMiddleton

+1

Upewnij się, że używasz 3 cyfr dla ms - '00: 00: 00: 01 'nie jest równe '00: 00: 00: 010' użyj sekundy. (testowane na MSSQL 2016) – Nick

0

Oto bardzo prosty fragment kodu C# do przetestowania CommandTimeout. Tworzy nowe polecenie, które będzie czekać przez 2 sekundy. Ustaw parametr CommandTimeout na 1 sekundę i zobaczysz wyjątek podczas jego uruchamiania. Ustawienie parametru CommandTimeout na 0 lub coś wyższego niż 2 będzie działać poprawnie. Nawiasem mówiąc, domyślny parametr CommandTimeout wynosi 30 sekund.

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

Jeśli jesteś w C# powinieneś prawdopodobnie użyć Thread.currentThread.sleep (60000) LUB Thread.sleep (60000), który robi to samo. W ten sposób Twoje opóźnienie jest odizolowane od twojej aplikacji.Następnie wywołaj późniejszą logikę bazy danych. –

+1

@ActionDan Korzystanie z Thread.Sleep nie pomoże jednak w zarządzaniu czasem CommandTimeout. Jako wymyślny przykład robi to, co jest napisane na pudełku. –

5
WAITFOR DELAY 'HH:MM:SS' 

wierzę, maksymalny czas może czekać do 23 godzin, 59 minut i 59 sekund.

Oto funkcja ceniona przez Skalar, aby pokazać jej użycie; poniższa funkcja przyjmie całkowity parametr sekund, który następnie przetłumaczy na HH: MM: SS i wykona go przy pomocy polecenia EXEC sp_executesql @sqlcode do zapytania. Poniższa funkcja służy tylko do celów demonstracyjnych, wiem, że nie nadaje się do celu tak naprawdę jako funkcja o wartościach skalarnych! :-)

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 

Jeśli chcesz, aby opóźnić dłużej niż 24 godzin, proponuję użyć @dni parametr, aby przejść przez kilka dni i zawinąć funkcji wykonywalnego wewnątrz pętli ... np.

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 
+0

** SQL Azure ** nie podoba to 'Tylko funkcje i niektóre rozszerzone procedury przechowywane mogą być wykonywane z poziomu funkcji. [Dokumenty MS dostarczają przykład przy użyciu Stored Procs] (https://docs.microsoft.com/ en-us/sql/t-sql/language-elements/waitfor-transact-sql # examples) - wygląda na to, że to podejście jest nieprawidłowe. – SliverNinja

1

można również "waitfor" a "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 
+1

Dlaczego nie używać polecenia "PRINT" zamiast "RAISERROR"? – slartidan