Perintah Tidur di T-SQL?

364

Apakah ada cara untuk menulis perintah T-SQL untuk membuatnya hanya tidur untuk jangka waktu tertentu? Saya menulis layanan web secara tidak sinkron dan saya ingin dapat menjalankan beberapa tes untuk melihat apakah pola asinkron benar-benar membuatnya lebih skalabel. Untuk "mengejek" layanan eksternal yang lambat, saya ingin dapat memanggil server SQL dengan skrip yang berjalan lambat, tetapi sebenarnya tidak memproses banyak hal.

skb
sumber
19
Pertanyaan yang adil! Saya mungkin ingin menggunakan ini kapan-kapan. Sebagai lengkap samping, ini adalah pertama kalinya saya pernah mendengar menginginkan DB lebih lambat;)
p.campbell
2
Saya bingung dengan menelepon layanan asinkron dari T-SQL.
jmucchiello

Jawaban:

616

Lihatlah perintah WAITFOR .

Misalnya

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

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

Perintah ini memungkinkan Anda memiliki tingkat presisi yang tinggi tetapi hanya akurat dalam 10ms - 16ms pada mesin biasa karena bergantung pada GetTickCount . Jadi, misalnya, panggilan WAITFOR DELAY '00:00:00:001'itu kemungkinan akan menghasilkan tidak menunggu sama sekali.

Sam Saffron
sumber
4
Adakah yang tahu cara menjalankan ini dari suatu Fungsi? Saya mendapatkan (mungkin benar), tetapi demi pengujian saya ingin menimpanya) 'Penggunaan yang tidak valid dari operator efek samping' WAITFOR 'dalam suatu fungsi ....
monojohnny
2
@onojohnny untuk mendapatkan SVF untuk menunggu, saya sudah mencoba jawaban Josh di bawah ini tetapi tidak berhasil. Sebagai gantinya saya hanya membuat lingkaran WHILE seperti ini: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
Pastikan Anda menggunakan 3 digit untuk ms - '00: 00: 00: 01 'tidak sama dengan '00: 00: 00: 010' gunakan yang kedua. (diuji pada MSSQL 2016)
Nick
Anda juga dapat mencoba TRANSAKSI BEGIN dan TRANSAKSI AKHIR jika Anda perlu memblokir sebuah tabel
Richárd Baldauf
9
WAITFOR DELAY 'HH:MM:SS'

Saya percaya waktu maksimum yang bisa ditunggu ini adalah 23 jam, 59 menit dan 59 detik.

Berikut adalah fungsi yang dihargai Scalar untuk menunjukkan penggunaannya; fungsi di bawah ini akan mengambil parameter integer detik, yang kemudian diterjemahkan menjadi HH: MM: SS dan mengeksekusinya menggunakan EXEC sp_executesql @sqlcodeperintah untuk kueri. Fungsi di bawah ini hanya untuk demonstrasi, saya tahu itu tidak cocok untuk tujuan benar-benar sebagai fungsi yang dihargai skalar! :-)

    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

JIKA Anda ingin menunda lebih lama dari 24 jam, saya sarankan Anda menggunakan parameter @Days untuk beberapa hari dan membungkus fungsi yang dapat dieksekusi di dalam sebuah loop ... mis.

    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
sumber
SQL Azure tidak suka Only functions and some extended stored procedures can be executed from within a function. MS Docs ini memberikan contoh menggunakan Stored Procs - sepertinya pendekatan ini tidak valid
SliverNinja - MSFT
5

Anda juga dapat "MENUNGGU" a "WAKTU":

    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
sumber
2
Mengapa tidak menggunakan PRINTbukan RAISERROR?
slartidan
4
Karena kalau tidak, Anda tidak akan melihat apa-apa sampai seluruh penantian selesai. RAISERROR memberi Anda opsi NOWAIT, sehingga akan menunjukkan kepada Anda pernyataan cetak (pada dasarnya) secara real time, yang bertentangan dengan ketika buffer penuh atau setelah batch selesai.
Jeremy Giaco
0

Ini adalah bagian yang sangat sederhana dari kode C # untuk menguji CommandTimeout. Ini menciptakan perintah baru yang akan menunggu selama 2 detik. Atur CommandTimeout ke 1 detik dan Anda akan melihat pengecualian saat menjalankannya. Mengatur CommandTimeout ke 0 atau sesuatu yang lebih tinggi dari 2 akan berjalan dengan baik. Omong-omong, CommandTimeout default adalah 30 detik.

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();
        }
      }
    }
  }
}
pengguna2192239
sumber
2
Jika Anda berada di c # Anda mungkin harus menggunakan Thread.currentThread.sleep (60000) ATAU Thread.sleep (60000) yang melakukan hal yang sama. Dengan cara itu keterlambatan Anda terisolasi ke aplikasi Anda. Kemudian panggil logika database Anda selanjutnya setelah itu.
Aksi Dan
2
@ActionDan Menggunakan Thread.Sleep tidak akan membantu menjalankan CommandTimeout, kan. Sebagai contoh buat, itu melakukan apa yang tertulis di kotak.
Richard Hauer