2009-03-20 28 views
309

Có cách nào để viết một lệnh T-SQL để chỉ làm cho nó ngủ trong một khoảng thời gian? 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 hay không. Để "chế giễu" 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 không thực sự xử lý một tấn công cụ.Lệnh Ngủ trong T-SQL?

+15

Fair câu hỏi! Tôi có thể muốn sử dụng điều này đôi khi. Là một 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;) –

+2

Tôi boggled bằng cách gọi một dịch vụ không đồng bộ từ T-SQL. – jmucchiello

Trả lời

511

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 một mức độ chính xác cao nhưng là only accurate within 10ms - 16ms trên một máy điển hình như nó dựa trên GetTickCount. Vì vậy, ví dụ, các cuộc gọi WAITFOR DELAY '00:00:00:001' có khả năng kết quả là không chờ đợi ở tất cả.

+2

Bất kỳ ai biết cách làm việc này từ một chức năng? Tôi nhận được (chính xác có thể), nhưng vì lợi ích của thử nghiệm tôi muốn ghi đè) 'Sử dụng không hợp lệ của một nhà điều hành tác dụng phụ' WAITFOR 'trong một chức năng .... – monojohnny

+1

@monojohnny để có được một SVF để chờ đợi, tôi' đã thử câu trả lời của Josh dưới đây nhưng nó không hoạt động. Thay vào đó, tôi chỉ tạo một vòng lặp WHILE như sau: 'CREATE FUNCTION [dbo]. [ForcedTimeout] (@ seconds int) trả về int là BEGIN DECLARE @endTime datetime2 (0) = DATEADD (SECOND, @seconds, GETDATE()) ; WHILE (GETDATE() <@endTime) BEGIN \t SET @endTime = @endTime; - không làm gì cả, nhưng SQL yêu cầu một câu lệnh. END' – GilesDMiddleton

+1

Đả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

0

Đây là một đoạn mã C# rất đơn giản để kiểm tra CommandTimeout với. 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 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 ở trong C#, bạn nên sử dụng Thread.currentThread.sleep (60000) HOẶC Thread.sleep (60000) 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 đó. –

+1

@ActionDan Using Thread.Sleep sẽ không giúp thực hiện CommandTimeout, đúng không. Như một ví dụ giả tạo, nó làm những gì được viết trên hộp. –

5
WAITFOR DELAY 'HH:MM:SS' 

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

Đây là hàm có giá trị vô hướng để cho biết cách sử dụng của nó; Hàm bên dưới sẽ lấy một tham số nguyên của giây, sau đó nó chuyển thành HH: MM: SS và thực hiện nó bằng lệnh EXEC sp_executesql @sqlcode để truy vấn. Chức năng 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ự như một hàm 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 đề nghị bạn sử dụng một tham số @Days để đi cho một số ngày và quấn 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 
+0

** SQL Azure ** không thích điều này 'Chỉ các hàm và một số thủ tục được lưu trữ mở rộng mới có thể được thực hiện từ bên trong một hàm.' [MS Documents cung cấp một ví dụ sử dụng Procs được lưu trữ] (https://docs.microsoft.com/ en-us/sql/t-sql/ngôn ngữ-nguyên tố/waitfor-transact-sql # ví dụ) - có vẻ như cách tiếp cận này không hợp lệ – SliverNinja

1

Bạn cũng có thể "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 
+1

Tại sao không sử dụng 'PRINT' thay vì' RAISERROR'? – slartidan

Các vấn đề liên quan