คำสั่ง Sleep ใน T-SQL


364

มีวิธีเขียนคำสั่ง T-SQL เพื่อให้มันหลับช่วงระยะเวลาหนึ่งหรือไม่ ฉันกำลังเขียนบริการเว็บแบบอะซิงโครนัสและฉันต้องการให้สามารถทำการทดสอบบางอย่างเพื่อดูว่ารูปแบบอะซิงโครนัสนั้นจะทำให้ขยายได้มากขึ้นหรือไม่ เพื่อที่จะ "เยาะเย้ย" บริการภายนอกที่ช้าฉันต้องการที่จะสามารถเรียกเซิร์ฟเวอร์ SQL ที่มีสคริปต์ที่ทำงานช้า แต่จริงๆแล้วมันไม่ได้ประมวลผลอะไรมากมาย


19
คำถามที่เป็นธรรม! ฉันอาจต้องการใช้บางครั้ง ในฐานะที่เป็นสมบูรณ์กันครั้งนี้เป็นครั้งแรกที่ผมเคยได้ยินของที่ต้องการฐานข้อมูลได้ช้า;)
p.campbell

2
ฉันเชื่อได้โดยการเรียกใช้บริการอะซิงโครนัสจาก T-SQL
jmucchiello

คำตอบ:


616

ดูที่คำสั่งWAITFOR

เช่น

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

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

คำสั่งนี้จะช่วยให้คุณมีระดับสูงของความแม่นยำ แต่ที่ถูกต้องเฉพาะภายใน 10ms - 16msบนเครื่องโดยทั่วไปในขณะที่มันอาศัยอยู่กับGetTickCount ตัวอย่างเช่นการโทรWAITFOR DELAY '00:00:00:001'มีแนวโน้มที่จะส่งผลให้ไม่ต้องรอเลย


4
ใครรู้วิธีทำให้สิ่งนี้ทำงานได้จากฟังก์ชั่น ฉันได้รับ (อาจถูกต้อง) แต่เพื่อทดสอบฉันต้องการแทนที่) 'การใช้ตัวดำเนินการด้านผลกระทบ' WAITFOR 'ไม่ถูกต้องภายในฟังก์ชัน ....
monojohnny

2
@monojohnny รับ SVF รอฉันลองคำตอบของ Josh ด้านล่าง แต่มันไม่ทำงาน แต่ฉันเพิ่งสร้างวง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
WHILE

3
ตรวจสอบให้แน่ใจว่าคุณใช้ 3 หลักสำหรับ ms - '00: 00: 00: 01 'ไม่เท่ากับ '00: 00: 00: 010' ใช้วินาที (ทดสอบกับ MSSQL 2016)
Nick

คุณยังสามารถลองเริ่มต้นการทำธุรกรรมและสิ้นสุดการทำธุรกรรมหากคุณต้องการบล็อกตาราง
Richárd Baldauf

9
WAITFOR DELAY 'HH:MM:SS'

ฉันเชื่อว่าเวลาสูงสุดที่สามารถรอได้คือ 23 ชั่วโมง 59 นาทีและ 59 วินาที

นี่คือฟังก์ชั่นที่มีคุณค่าของสเกลาร์เพื่อแสดงการใช้งาน ฟังก์ชั่นด้านล่างจะใช้พารามิเตอร์จำนวนเต็มวินาทีซึ่งมันจะแปลเป็น HH: MM: SS และดำเนินการโดยใช้EXEC sp_executesql @sqlcodeคำสั่งเพื่อสอบถาม ฟังก์ชั่นด้านล่างสำหรับการสาธิตเท่านั้นฉันรู้ว่ามันไม่เหมาะสำหรับวัตถุประสงค์จริงๆในฐานะฟังก์ชันที่มีค่าสเกลา :-)

    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

หากคุณต้องการหน่วงเวลานานกว่า 24 ชั่วโมงฉันขอแนะนำให้คุณใช้พารามิเตอร์ @Days เป็นเวลาหลายวันและตัดการทำงานของฟังก์ชันภายในลูป ... เช่น

    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ไม่ชอบOnly functions and some extended stored procedures can be executed from within a function. เอกสาร MSนี้แสดงตัวอย่างโดยใช้ Stored Procs - ดูเหมือนว่าวิธีการนี้ไม่ถูกต้อง
SliverNinja - MSFT

5

นอกจากนี้คุณยังสามารถ "WAITFOR" เป็น "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

2
ทำไมไม่ใช้PRINTแทนRAISERROR?
slartidan

4
เพราะมิฉะนั้นคุณจะไม่เห็นอะไรเลยจนกระทั่งหลังจากการรอคอยทั้งหมดเสร็จสิ้น RAISERROR ให้ตัวเลือก NOWAIT แก่คุณดังนั้นมันจะแสดงคำสั่งการพิมพ์ (เป็นหลัก) ในแบบเรียลไทม์ซึ่งตรงข้ามกับเมื่อบัฟเฟอร์เต็มหรือหลังจากแบตช์เสร็จสมบูรณ์
Jeremy Giaco

0

นี่คือโค้ด C # ที่ง่ายมากในการทดสอบ CommandTimeout ด้วย มันสร้างคำสั่งใหม่ซึ่งจะรอ 2 วินาที ตั้งค่า CommandTimeout เป็น 1 วินาทีและคุณจะเห็นข้อยกเว้นเมื่อเรียกใช้ การตั้งค่า CommandTimeout เป็น 0 หรือบางอย่างที่สูงกว่า 2 จะทำงานได้ดี โดยค่าเริ่มต้น CommandTimeout คือ 30 วินาที

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
หากคุณอยู่ใน c # คุณควรใช้ Thread.currentThread.sleep (60000) หรือ Thread.sleep (60000) ซึ่งทำสิ่งเดียวกัน ด้วยวิธีนี้ความล่าช้าของคุณจะถูกแยกไปยังแอปพลิเคชันของคุณ จากนั้นเรียกตรรกะฐานข้อมูลที่ตามมาของคุณในภายหลัง
การกระทำ Dan

2
@ActionDan ใช้ Thread.Sleep จะไม่ช่วยในการออกกำลังกาย CommandTimeout แม้ว่ามันจะเป็น เป็นตัวอย่างที่วางแผนไว้มันทำสิ่งที่เขียนบนกล่อง
Richard Hauer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.