2009-03-20 9 views
309

Est-il possible d'écrire une commande T-SQL pour l'éteindre pendant un certain temps? J'écris un service Web de manière asynchrone et je veux être en mesure d'exécuter des tests pour voir si le modèle asynchrone va vraiment le rendre plus évolutif. Afin de "se moquer" d'un service externe qui est lent, je veux pouvoir appeler un serveur SQL avec un script qui tourne lentement, mais qui ne traite pas beaucoup de choses.Commande de veille dans T-SQL?

+15

question juste! Je pourrais vouloir l'utiliser un jour. En aparté, c'est la première fois que j'entends parler de vouloir que la DB soit plus lente;) –

+2

Je suis bogué en appelant un service asynchrone de T-SQL. – jmucchiello

Répondre

511

regard sur la commande WAITFOR

Par exemple.

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

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

Cette commande vous permet un haut degré de précision, mais est only accurate within 10ms - 16ms sur une machine typique car elle repose sur GetTickCount. Ainsi, par exemple, l'appel WAITFOR DELAY '00:00:00:001' est susceptible d'entraîner aucune attente du tout.

+2

Quelqu'un sait comment faire fonctionner une fonction? Je reçois (correctement probablement), mais pour des raisons de test, je voudrais remplacer) 'Utilisation invalide d'un opérateur d'effet secondaire' WAITFOR 'dans une fonction .... – monojohnny

+1

@monojohnny pour obtenir un SVF à attendre, je' J'ai essayé la réponse de Josh ci-dessous mais ça n'a pas marché. Au lieu de cela, je crée simplement une boucle WHILE comme ceci: 'CREATE FUNCTION [dbo]. [ForcedTimeout] (@ secondes int) renvoie int comme BEGIN DECLARE @endTime datetime2 (0) = DATEADD (SECOND, @seconds, GETDATE()) ; PENDANT (GETDATE() <@endTime) BEGIN \t SET @endTime = @endTime; - Ne faites rien, mais SQL nécessite une déclaration. END' – GilesDMiddleton

+1

Assurez-vous d'utiliser 3 chiffres pour les ms - '00: 00: 00: 01' n'est pas égal à '00: 00: 00: 010' utilisez le second. (testé sur MSSQL 2016) – Nick

0

Voici un morceau de code C# très simple pour tester le CommandTimeout avec. Il crée une nouvelle commande qui attendra 2 secondes. Définissez CommandTimeout sur 1 seconde et vous verrez une exception lors de son exécution. Définir le CommandTimeout à 0 ou quelque chose de plus élevé que 2 fonctionnera correctement. Par ailleurs, le CommandTimeout par défaut est de 30 secondes.

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

Si vous êtes en C#, vous devriez probablement utiliser Thread.currentThread.sleep (60000) ou Thread.sleep (60000) qui fait la même chose. De cette façon, votre délai est isolé pour votre application.Appelez ensuite votre logique de base de données ultérieure. –

+1

@ActionDan Utilisation de Thread.Sleep ne va pas aider à exercer le CommandTimeout, n'est-ce pas. Comme un exemple artificiel, il fait ce qui est écrit sur la boîte. –

5
WAITFOR DELAY 'HH:MM:SS' 

je crois que le temps maximum, cela peut attendre 23 heures, 59 minutes et 59 secondes.

Voici une fonction scalaire pour montrer son utilisation; la fonction ci-dessous prendra un paramètre entier de secondes, qu'elle traduit ensuite en HH: MM: SS et l'exécute en utilisant la commande EXEC sp_executesql @sqlcode pour interroger. La fonction ci-dessous est à titre de démonstration seulement, je sais que ce n'est pas vraiment utile pour une fonction scalaire! :-)

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 

Si vous souhaitez retarder plus de 24 heures, je vous suggère d'utiliser un paramètre @Days aller pour un certain nombre de jours et envelopper la fonction exécutable dans une boucle ... par exemple.

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 ** n'aime pas ça 'Seules les fonctions et certaines procédures stockées étendues peuvent être exécutées à partir d'une fonction.' [MS Docs fournit un exemple en utilisant Sted Procs] (https://docs.microsoft.com/ en-us/sql/t-sql/langue-elements/waitfor-transact-sql # examples) - ressemble à cette approche invalide – SliverNinja

1

Vous pouvez également "WAITFOR" un "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

Pourquoi ne pas utiliser 'PRINT' au lieu de' RAISERROR'? – slartidan

Questions connexes