405 votes

Commande Sleep en T-SQL ?

Existe-t-il un moyen d'écrire une commande T-SQL pour le faire dormir pendant un certain temps ? Je suis en train d'écrire un service web de manière asynchrone et je veux pouvoir effectuer des tests pour voir si le modèle asynchrone va vraiment le rendre plus évolutif. Afin de "simuler" un service externe qui est lent, je veux pouvoir appeler un serveur SQL avec un script qui s'exécute lentement, mais qui ne traite pas réellement une tonne de choses.

22 votes

Bonne question ! Je pourrais avoir envie de l'utiliser un jour. En passant, c'est la première fois que j'entends parler de vouloir que la BD soit plus lente ;)

3 votes

L'appel d'un service asynchrone à partir de T-SQL me laisse perplexe.

700voto

Sam Saffron Points 56236

Regardez le ATTENDRE comando.

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 seulement précis à 10ms - 16ms près sur une machine classique car il repose sur GetTickCount . Ainsi, par exemple, l'appel WAITFOR DELAY '00:00:00:001' est susceptible d'aboutir à une absence totale d'attente.

4 votes

Quelqu'un sait-il comment faire pour que cela fonctionne à partir d'une fonction ? J'ai obtenu (probablement correctement), mais pour des raisons de test, je voudrais contourner) 'Invalid use of a side-effecting operator 'WAITFOR' within a function.....

2 votes

@monojohnny pour faire attendre un SVF, j'ai essayé la réponse de Josh ci-dessous mais ça n'a pas marché. A la place, je crée simplement 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

4 votes

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)

13voto

Josh Harris Points 309
WAITFOR DELAY 'HH:MM:SS'

Je crois que le temps maximum d'attente est de 23 heures, 59 minutes et 59 secondes.

Voici une fonction à valeur scalaire pour montrer son utilisation ; la fonction ci-dessous prend un paramètre entier de secondes, qu'elle traduit ensuite en HH:MM:SS et l'exécute à l'aide de la fonction EXEC sp_executesql @sqlcode pour effectuer une requête. La fonction ci-dessous n'est qu'une démonstration, je sais qu'elle n'est pas vraiment adaptée à 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 jusqu'à un certain nombre de jours et d'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

7voto

Jeremy Giaco Points 61

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

1voto

user2192239 Points 11

Voici un morceau de code C# très simple pour tester le CommandTimeout. Il crée une nouvelle commande qui attendra 2 secondes. Si vous définissez le CommandTimeout à 1 seconde, vous verrez apparaître une exception lors de son exécution. Si vous fixez le CommandTimeout à 0 ou à une valeur supérieure à 2, l'exécution sera parfaite. À propos, 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 votes

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é de votre application. Appelez ensuite votre logique de base de données ultérieure.

4 votes

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X