Lệnh ngủ trong T-SQL?


364

Có cách nào để viết một lệnh T-SQL để làm cho nó ngủ trong một khoảng thời gian không? Tôi đang viết một dịch vụ web không đồng bộ và tôi muốn có thể chạy một số thử nghiệm để xem liệu mẫu không đồng bộ có thực sự làm cho nó có khả năng mở rộng hơn không. Để "chế nhạo" một dịch vụ bên ngoài chậm, tôi muốn có thể gọi một máy chủ SQL với một tập lệnh chạy chậm, nhưng thực tế không xử lý được cả tấn công cụ.


19
Câu hỏi công bằng! Tôi có thể muốn sử dụng điều này đôi khi. Như một sự hoàn toàn sang một bên, đây là lần đầu tiên tôi từng nghe nói muốn DB chậm hơn;)
p.campbell

2
Tôi gặp khó khăn khi gọi một dịch vụ không đồng bộ từ T-SQL.
jmucchiello

Câu trả lời:


616

Nhìn vào lệnh WAITFOR .

Ví dụ

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

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

Lệnh này cho phép bạn có độ chính xác cao nhưng chỉ chính xác trong vòng 10ms - 16ms trên một máy thông thường vì nó phụ thuộc vào GetTickCount . Vì vậy, ví dụ, cuộc gọi WAITFOR DELAY '00:00:00:001'có khả năng dẫn đến không chờ đợi gì cả.


4
Bất cứ ai cũng biết làm thế nào để làm việc này từ Chức năng? Tôi nhận được (có lẽ chính xác), nhưng vì mục đích thử nghiệm, tôi muốn ghi đè lên) 'Việc sử dụng không hợp lệ của toán tử tác dụng phụ' WAITFOR 'trong một chức năng ....
monojohnny

2
@monojohnny để có được một SVF để chờ đợi, tôi đã thử câu trả lời của Josh bên dưới nhưng nó không hoạt động. Thay vào đó tôi chỉ tạo một vòng lặp WHILE như thế này: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
Đảm bảo bạn sử dụng 3 chữ số cho ms - '00: 00: 00: 01 'không bằng '00: 00: 00: 010' sử dụng số thứ hai. (đã thử nghiệm trên MSSQL 2016)
Nick

bạn cũng có thể thử BEGIN TRANSACTION và END TRANSACTION nếu bạn cần chặn một bảng
Richárd Baldauf

9
WAITFOR DELAY 'HH:MM:SS'

Tôi tin rằng thời gian tối đa này có thể chờ là 23 giờ, 59 phút và 59 giây.

Đây là một hàm có giá trị vô hướng để hiển thị việc sử dụng nó; hàm dưới đây sẽ lấy tham số nguyên là giây, sau đó nó chuyển thành HH: MM: SS và thực thi nó bằng EXEC sp_executesql @sqlcodelệnh để truy vấn. Hàm dưới đây chỉ dành cho trình diễn, tôi biết nó không phù hợp với mục đích thực sự là hàm có giá trị vô hướng! :-)

    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

NẾU bạn muốn trì hoãn lâu hơn 24 giờ, tôi khuyên bạn nên sử dụng tham số @Days để đi trong một số ngày và bọc chức năng thực thi bên trong một vòng lặp ... ví dụ:

    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

SQL Azure không giống như Only functions and some extended stored procedures can be executed from within a function. MS Docs này cung cấp một ví dụ sử dụng Procs được lưu trữ - có vẻ như cách tiếp cận này không hợp lệ
SliverNinja - MSFT

5

Bạn cũng có thể "CHỜ ĐỢI" một "THỜI GIAN":

    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

2
Tại sao không sử dụng PRINTthay thế RAISERROR?
slartidan

4
Bởi vì nếu không bạn sẽ không thấy gì cho đến khi toàn bộ chờ đợi kết thúc. RAISERROR cung cấp cho bạn tùy chọn NOWAIT, do đó, nó sẽ hiển thị cho bạn các bản in (về cơ bản) trong thời gian thực, trái ngược với khi bộ đệm đầy hoặc sau khi lô được hoàn thành.
Jeremy Giaco

0

Đây là một đoạn mã C # rất đơn giản để kiểm tra CommandTimeout. Nó tạo ra một lệnh mới sẽ chờ trong 2 giây. Đặt CommandTimeout thành 1 giây và bạn sẽ thấy một ngoại lệ khi chạy nó. Đặt CommandTimeout thành 0 hoặc thứ gì đó cao hơn 2 sẽ chạy tốt. Nhân tiện, CommandTimeout mặc định là 30 giây.

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
Nếu bạn đang ở c #, có lẽ bạn nên sử dụng Thread.cienThread.s ngủ (60000) HOẶC Thread.s ngủ (60000) cũng làm điều tương tự. Bằng cách đó, sự chậm trễ của bạn bị cô lập với ứng dụng của bạn. Sau đó gọi logic cơ sở dữ liệu tiếp theo của bạn sau đó.
Hành động Dan

2
@ActionDan Sử dụng Thread.S ngủ sẽ không giúp thực hiện CommandTimeout, đúng vậy. Như một ví dụ giả định, nó thực hiện những gì được viết trên hộp.
Richard Hauer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.