Commande Sleep dans T-SQL?

364

Existe-t-il un moyen d'écrire une commande T-SQL pour la faire simplement dormir pendant une période de temps? J'écris un service Web de manière asynchrone et je veux pouvoir 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 s'exécute lentement, mais ne traite pas réellement une tonne de choses.

skb
la source
19
Juste question! 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;)
p.campbell
2
Je suis stupéfait en appelant un service asynchrone à partir de T-SQL.
jmucchiello

Réponses:

616

Regardez 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 n'est précise que dans un délai de 10 à 16 ms sur une machine typique car elle repose sur GetTickCount . Ainsi, par exemple, l'appel WAITFOR DELAY '00:00:00:001'n'entraînera probablement aucune attente.

Sam Saffron
la source
4
Quelqu'un sait comment faire fonctionner cela à partir d'une fonction? Je reçois (correctement probablement), mais pour des raisons de test, je voudrais passer outre) 'Utilisation non valide d'un opérateur à effets secondaires' WAITFOR 'dans une fonction ....
monojohnny
2
@monojohnny pour faire attendre un SVF, j'ai essayé la réponse de Josh ci-dessous mais cela n'a pas fonctionné. Au lieu de cela, je crée juste une boucle WHILE comme ceci: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
Assurez-vous que vous utilisez 3 chiffres pour le ms - '00: 00: 00: 01 'n'est pas égal à '00: 00: 00: 010' utilisez le second. (testé sur MSSQL 2016)
Nick
vous pouvez également essayer DEBUTER TRANSACTION et FIN TRANSACTION si vous avez besoin de bloquer une table
Richárd Baldauf
9
WAITFOR DELAY 'HH:MM:SS'

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

Voici une fonction à valeur scalaire pour montrer son utilisation; la fonction ci-dessous prendra un paramètre entier de secondes, qu'elle traduira ensuite en HH: MM: SS et l'exécutera en utilisant la EXEC sp_executesql @sqlcodecommande pour interroger. La fonction ci-dessous est uniquement à des fins de démonstration, je sais qu'elle ne convient pas vraiment à une fonction à valeur 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 pour aller pendant un certain nombre de jours et envelopper l'exécutable de la fonction 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
Josh Harris
la source
SQL Azure n'aime pas cela Only functions and some extended stored procedures can be executed from within a function. MS Docs fournit un exemple d'utilisation de processus stockés - il semble que cette approche ne soit pas valide
SliverNinja - MSFT
5

Vous pouvez également "ATTENDRE" un "TEMPS":

    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
Jeremy Giaco
la source
2
Pourquoi ne pas utiliser à la PRINTplace de RAISERROR?
slartidan
4
Sinon, vous ne verriez rien avant la fin de l'attente. RAISERROR vous donne l'option NOWAIT, donc il vous montrera des instructions d'impression (essentiellement) en temps réel, par opposition à quand le tampon est plein ou après la fin du batch.
Jeremy Giaco
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. La définition de CommandTimeout sur 0 ou quelque chose de supérieur à 2 s'exécute correctement. Soit dit en passant, 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();
        }
      }
    }
  }
}
user2192239
la source
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 retard est isolé de votre application. Appelez ensuite la logique de base de données suivante.
Action Dan
2
@ActionDan Utiliser Thread.Sleep ne va pas aider à exercer le CommandTimeout, n'est-ce pas? À titre d'exemple artificiel, il fait ce qui est écrit sur la boîte.
Richard Hauer