È necessario scrivere un comando T-SQL per farlo dormire per un periodo di tempo? Sto scrivendo un servizio web in modo asincrono e voglio essere in grado di eseguire alcuni test per vedere se il pattern asincrono lo renderà davvero più scalabile. Per "prendere in giro" un servizio esterno che è lento, voglio essere in grado di chiamare un server SQL con uno script che funziona lentamente, ma in realtà non sta elaborando un sacco di cose.Sleep Command in T-SQL?
risposta
un'occhiata al comando WAITFOR
Eg.
-- wait for 1 minute
WAITFOR DELAY '00:01'
-- wait for 1 second
WAITFOR DELAY '00:00:01'
Questo comando permette un alto grado di precisione, ma è only accurate within 10ms - 16ms su una macchina tipica in quanto si basa su GetTickCount. Ad esempio, la chiamata WAITFOR DELAY '00:00:00:001'
rischia di non attendere affatto.
Qualcuno sa come farlo funzionare da una funzione? Ottengo (correttamente probabilmente), ma per motivi di test vorrei eseguire l'override) 'Uso non valido di un operatore di effetti collaterali' WAITFOR 'all'interno di una funzione .... – monojohnny
@monojohnny per ottenere un SVF in attesa, I' Ho provato la risposta di Josh in basso ma non ha funzionato. Invece creo solo un ciclo WHILE come questo: 'CREATE FUNCTION [dbo]. [ForcedTimeout] (@ secondi int) restituisce int come INIZIO DECLARE @endTime datetime2 (0) = DATEADD (SECONDO, @seconds, GETDATE()) ; WHILE (GETDATE() <@endTime) BEGIN \t SET @endTime = @endTime; - non fare nulla, ma SQL richiede una dichiarazione. END' – GilesDMiddleton
Assicurati di utilizzare 3 cifre per il ms - '00: 00: 00: 01 'non è uguale a '00: 00: 00: 010' usa il secondo. (testato su MSSQL 2016) – Nick
Ecco un pezzo molto semplice di codice C# per testare CommandTimeout con. Crea un nuovo comando che attenderà per 2 secondi. Imposta CommandTimeout a 1 secondo e vedrai un'eccezione durante l'esecuzione. L'impostazione di CommandTimeout su 0 o su un valore superiore a 2 funzionerà correttamente. A proposito, il CommandTimeout predefinito è 30 secondi.
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();
}
}
}
}
}
Se si è in C#, si dovrebbe probabilmente usare Thread.currentThread.sleep (60000) OR Thread.sleep (60000) che fa la stessa cosa. In questo modo il tuo ritardo è isolato dalla tua applicazione.Quindi chiamare la logica successiva del database in seguito. –
@ActionDan L'uso di ThreadSleep non aiuta a utilizzare CommandTimeout, vero? Come esempio forzato, fa ciò che è scritto sulla scatola. –
WAITFOR DELAY 'HH:MM:SS'
Credo che il tempo massimo questo può attendere è di 23 ore, 59 minuti e 59 secondi.
Ecco una funzione con valori scalari per mostrare che è in uso; la funzione sottostante prenderà un parametro intero di secondi, che poi tradurrà in HH: MM: SS e lo eseguirà usando il comando EXEC sp_executesql @sqlcode
per interrogare. Sotto la funzione è solo per la dimostrazione, so che non è adatto allo scopo davvero come una funzione scalare! :-)
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
Se si desidera ritardare più di 24 ore, vi suggerisco di utilizzare un parametro @Days di andare per un numero di giorni e avvolgere l'eseguibile funzione all'interno di un ciclo ... ad es.
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
** A SQL Azure ** non piace "Solo le funzioni e alcune stored procedure estese possono essere eseguite all'interno di una funzione. [MS Docs fornisce un esempio utilizzando Processi memorizzati] (https://docs.microsoft.com/ en-us/sql/t-sql/lingua-elements/waitfor-transact-sql # esempi) - questo approccio non è valido – SliverNinja
È inoltre possibile "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
Perché non usare 'PRINT' invece di' RAISERROR'? – slartidan
Fiera domanda! Potrei voler usare questo a volte. Per completezza, questa è la prima volta che ho sentito parlare di voler rallentare il DB;) –
Sono impazzito chiamando un servizio asincrono da T-SQL. – jmucchiello