SQL Server, используя таблицу в качестве очереди - PullRequest
6 голосов
/ 14 января 2011

Я использую SQL Server 2008 R2 в качестве механизма очередей. Я добавляю элементы в таблицу, и внешний сервис считывает и обрабатывает эти элементы. Это прекрасно работает, но не хватает одной вещи - мне нужен механизм, с помощью которого я могу попытаться выбрать одну строку из таблицы и, если ее нет, блокировать до тех пор, пока она не будет (предпочтительно в течение определенного периода времени).

Кто-нибудь может посоветовать, как мне этого добиться?

Ответы [ 5 ]

9 голосов
/ 14 января 2011

Единственный способ добиться блокировки без пулов - WAITFOR (RECEIVE).Это подразумевает очереди компонента Service Broker со всеми дополнительными издержками.

Если вы используете обычные таблицы в качестве очередей , вы не сможете добиться блокировки без опроса.Вы должны опрашивать очередь, запрашивая операцию удаления, и если она ничего не возвращает, спите и повторите попытку позже.

Боюсь, что здесь я не соглашусь с Андомаром: хотя его ответ работает как общий вопрос: есть ли строки в таблице?когда дело доходит до постановки в очередь, из-за занятого характера наложения очереди / удаления, проверка на наличие строк, как это (почти) гарантированный тупик под нагрузкой.Когда дело доходит до использования таблиц в качестве очереди, нужно всегда придерживаться базовых операций постановки / удаления очереди и не пытаться делать что-то необычное.

7 голосов
/ 04 мая 2011

"с тех пор как в SQL Server 2005 было введено предложение OUTPUT, использование таблиц в качестве очередей больше не является сложной проблемой". Отличный пост о том, как это сделать.

http://rusanu.com/2010/03/26/using-tables-as-queues/

2 голосов
/ 14 января 2011

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

Вы можете зацикливаться и проверять наличие новых строк каждую секунду:

while not exists (select * from QueueTable)
    begin
    wait for delay '00:01'
    end

Отказ от ответственности: это не тот код, который я бы использовал для производственной системы, но он выполняет то, что вы просите.

1 голос
/ 14 января 2011

Предыдущий комментатор, который предлагал использовать Service Broker, вероятно, имел лучший ответ.Компонент Service Broker позволяет вам по существу блокировать, ожидая большего ввода.

Если компонент Service Broker перегибает, вам следует рассмотреть другой подход к вашей проблеме.Можете ли вы предоставить более подробную информацию о том, что вы пытаетесь сделать?

0 голосов
/ 20 октября 2013

Позвольте мне поделиться с вами своим опытом в этой области, вы можете найти его полезным.

Моя команда впервые использовала транзакционные очереди MSMQ, которые будут обслуживать наши асинхронные службы (будь то хостинг IIS или WAS).Самой большой проблемой, с которой мы столкнулись, были проблемы MS DTC при большой нагрузке, например, 100+ сообщений в секунду;все, что потребовалось, - это одна медленная операция с базой данных где-то, чтобы начать вызывать исключения тайм-аута, и MS DTC, если можно так выразиться, разрушил бы дом (транзакции фактически потерялись бы, если бы все стало достаточно плохо), и хотя мы не на 100% уверены в корнеПо сей день мы подозреваем, что MS DTC в кластерной среде имеет некоторые серьезные проблемы.

Из-за этого мы начали искать другие решения.Служебная шина для Windows Server (локальная версия Azure Service Bus) выглядела многообещающе, но не транзакционной, поэтому не отвечала нашим требованиям.

Мы наконец-то выбрали подход «по-вашему».подход, предложенный нам ребятами, которые создали сервисную шину Azure из-за наших требований к транзакциям.По сути, мы следовали модели рабочей роли Azure для рабочей роли, которая будет передаваться через некоторую очередь;модель блокировки опросов.

Честно говоря, для нас это было намного лучше, чем все остальное, что мы использовали.Псевдокод для такой службы:

hasMsg = true

while(true)

    if(!hasMsg)
         sleep

    msg = GetNextMessage

    if(msg == null)
        hasMsg = false
    else
        hasMsg = true

    Process(msg);

Мы обнаружили, что загрузка ЦП при этом значительно ниже (ниже, чем у традиционных служб WCF).

Сложная задача, конечно, заключается в обработкесделки.Если вы хотите, чтобы несколько экземпляров вашей службы читались из очереди, вам нужно будет использовать read-past / updlock в вашем sql, а также включить службу .net в транзакции таким образом, чтобыобратно в случае сбоя службы.в этом случае вы захотите использовать в качестве таблиц очереди повторов / отравлений в дополнение к обычным очередям.

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