WAITFOR DELAY не действует отдельно в каждом цикле WHILE - PullRequest
1 голос
/ 10 апреля 2019

Я учил себя использовать циклы WHILE и решил попробовать сделать увлекательный симулятор русской рулетки.То есть запрос, который случайным образом ВЫБРАЕТ (или ПЕЧАТАЕТ) до 6 операторов (по одному для каждой из камер в револьвере), последний из которых гласит «ты умрешь!»и все, что до этого читало: «ты выжил».

Я сделал это, сначала создав таблицу #Nums, которая содержит числа 1-6 в случайном порядке.Затем я получаю цикл WHILE следующим образом, с BREAK, если выбрана камера, содержащая «пулю» (1) (я знаю, что есть более простые способы выбора случайного числа, но это адаптировано из чего-то еще, с чем я играл дои я не был заинтересован в его изменении):

SET NOCOUNT ON

CREATE TABLE #Nums ([Num] INT)
DECLARE @Count INT = 1
DECLARE @Limit INT = 6
DECLARE @Number INT

WHILE @Count <= @Limit
BEGIN
SET @Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*@Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = @Number)
BEGIN
INSERT INTO #Nums VALUES(@Number)
SET @Count += 1
END
END

DECLARE @Chamber INT

WHILE 1=1
BEGIN
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      SELECT 'you die!' [Unlucky...]
      BREAK
    END
  SELECT
   'you survive.' [Phew...]
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

DROP TABLE #Nums

Это прекрасно работает, но все результаты появляются мгновенно, и я хочу добавить задержку между ними, чтобы добавить немного напряжения.

Я попытался использовать WAITFOR DELAY следующим образом:

WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      SELECT 'you die!' [Unlucky...]
      BREAK
    END
  SELECT
   'you survive.' [Phew...]
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

Я ожидал, что WAITFOR DELAY первоначально вызовет 3-секундную задержку, затем будет выполнен первый оператор SELECT и появится текст втаблица результатов, а затем, если предположить, что камера под напряжением не была выбрана, чтобы была еще 3-секундная задержка и т. д., пока не будет выбрана камера под напряжением.

Однако, прежде чем что-либо появится в моей таблице результатов,на количество выполняемых операторов SELECT приходится 3 секунды, после чего все результаты появляются одновременно.Я попытался использовать PRINT вместо SELECT, но столкнулся с той же проблемой.

Очевидно, что здесь что-то не хватает - кто-нибудь может пролить свет на это?

1 Ответ

3 голосов
/ 10 апреля 2019

Это называется буферизацией. Сервер не хочет возвращать только частично полный ответ, потому что большую часть времени приходится учитывать все накладные расходы сети. Множество очень маленьких пакетов дороже, чем несколько больших пакетов 1 .

Если вы используете RAISERROR (не беспокойтесь о названии здесь, где мы используем 10), вы можете указать NOWAIT, чтобы сказать «отправить это немедленно». Нет эквивалента для PRINT или возвращаемых наборов результатов:

SET NOCOUNT ON

CREATE TABLE #Nums ([Num] INT)
DECLARE @Count INT = 1
DECLARE @Limit INT = 6
DECLARE @Number INT

WHILE @Count <= @Limit
BEGIN
SET @Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*@Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = @Number)
BEGIN
INSERT INTO #Nums VALUES(@Number)
SET @Count += 1
END
END

DECLARE @Chamber INT

WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
  SET @Chamber = (SELECT TOP 1 [Num] FROM #Nums)
    IF @Chamber = 1
    BEGIN
      RAISERROR('you die!, Unlucky',10,1) WITH NOWAIT
      BREAK
    END
   RAISERROR('you survive., Phew...',10,1) WITH NOWAIT
  DELETE FROM #Nums WHERE [Num] = @Chamber
END

DROP TABLE #Nums

Как Ларну уже упоминал в комментариях , это не хорошее использование T-SQL.

SQL является языком, ориентированным на множество. Мы пытаемся не писать процедурный код (сделайте это, затем сделайте это, затем запустите этот блок кода несколько раз). Мы стараемся предоставить серверу как можно больше в одном запросе и дать it понять, как его обработать. Хотя T-SQL имеет языковую поддержку для циклов, мы стараемся избегать их, если это возможно.


1 Я использую пакеты очень здесь. Обратите внимание, что он применяет одну и ту же оптимизацию независимо от того, какая опция сети (или no-network-local-memory) фактически используется для передачи соединения между клиентом и сервером.

...