Индексы против стратегии блокировки в реализации очереди заданий SQL - PullRequest
0 голосов
/ 22 ноября 2011

В SQL 2008+ следующая таблица очередей и операции постановки в очередь предназначены для обеспечения эффективной очереди заданий в потоках между несколькими генераторами и потребителями в произвольных именованных очередях в необязательной частично упорядоченной последовательности.Тривиальная поддержка обработки вредоносных сообщений с помощью RetryLater (), FailNow (), Reset () (не показана).

CREATE TABLE [dbo].[Queue](
    [ID] BIGINT IDENTITY(1,1) NOT NULL CONSTRAINT [PK_Queue] PRIMARY KEY,
    [PredecessorID] BIGINT NULL,
    [QueueName] NVARCHAR(255) NOT NULL,
    [DataType] NVARCHAR(255) NOT NULL,
    [Data] NVARCHAR(MAX) NOT NULL,
    [RetriesRemaining] INT CONSTRAINT [CHK_RetryCount] CHECK ([RetriesRemaining] IS NULL OR 0 <= [RetriesRemaining]),
    [IsFailed] AS (CASE WHEN [RetriesRemaining] IS NULL OR 0 < [RetriesRemaining] THEN 0 ELSE 1 END) PERSISTED,
    [QueuedOnUTC] DATETIME NOT NULL DEFAULT (GETUTCDATE()),
    [DelayUntilUTC] DATETIME NULL,
    [LastFailedOnUTC] DATETIME NULL,
    [LastFailure] NVARCHAR(MAX)
)

-- Enqueue
INSERT INTO [dbo].[Queue]
(
    [PredecessorID],
    [QueueName],
    [DataType],
    [Data],
    [RetriesRemaining]
)
VALUES
(
    @PredecessorID,
    @QueueName,
    @DataType,
    @Data,
    @RetriesRemaining
)

-- Dequeue
SELECT
    [Dequeued].[ID],
    [Dequeued].[QueueName],
    [Dequeued].[DataType],
    [Dequeued].[Data]
FROM
    [dbo].[Queue] AS [Dequeued] WITH (ROWLOCK, UPDLOCK, READPAST)
LEFT JOIN
    [dbo].[Queue] AS [Predecessor] ON
    [Dequeued].[PredecessorID] = [Predecessor].[ID]
WHERE
    [Dequeued].[IsFailed] = 0
    AND [Dequeued].[QueueName] = @QueueName
    AND ([Dequeued].[DelayUntilUTC] IS NULL OR [Dequeued].[DelayUntilUTC] < GETUTCDATE())
    AND [Predecessor].[ID] IS NULL

Потребительские транзакции остаются открытыми с до Dequeue () через обработку на стороне приложения и до DELETE, RetryLater () или FailNow ().

  • Является ли этот дизайн звуком?
  • Эта установка свободна от блокировки?
  • Что отрицательно Может ли IDX_Queue_IsFailed_QueueName_DelayUntilUTC или другие индексы повлиять на взаимную блокировку?
  • Какие другие индексы полезны?
  • Как разделение таблиц (queueName) или другие функции могут улучшить масштабируемость?
  • В соответствии с задумкой, Генераторы сигнализируют Потребителям через внешний механизм, что данные были помещены в очередь, чтобы избежать жесткого опроса.Вместо этого (и без SQL ServiceBroker) есть способ использовать блокировки SQL для эффективной блокировки получателя, для которого нет доступных строк, пока генератор не записал в именованную очередь?

    CREATE INDEX [IDX_Queue_IsFailed_QueueName_DelayUntilUTC] ON[dbo]. [Queue] ([IsFailed], [QueueName], [DelayUntilUTC])

Кроме того, я предполагаю, что OrderBy не имеет значения, если мы всегда получаем одинбез предшественника.

1 Ответ

2 голосов
/ 23 ноября 2011

Мой 2с на этом:

  • в первую очередь очередь считывается.Это должна быть запись.Используйте UPDATE WITH OTUPUT.
  • , не используйте NULL для DelayUntilUTC, используйте текущий UTC во время вставки.Выражения «ИЛИ» могут запускать сканирование, что приводит к взаимным блокировкам, помимо ухудшения производительности
  • кластерный индекс [Queue] должен быть следующим: (IsFailed, QueueName, DelayUntilUTC).
  • делает первичный ключ некластеризованным или вообще избавляется от него, тождества в очередях почти не используются.
  • избавляются от Предшественника и LEFT JOIN.Вы будете ругаться за устранение тупиковых ситуаций до тех пор, пока с ними не уйдете.

Я понимаю, что последний элемент, вероятно, очень труден для восприятия, но в реляционной таблице в принципе невозможно достичь корреляционной блокировки с readpast.

Я подробно говорил об этой теме в Использование таблиц в качестве очередей .Очереди должны быть простыми для масштабирования.Ваш дизайн слишком модный и не сработает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...