2011-01-14 2 views
6

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

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

+0

Вопрос был задан много раз на SO; пожалуйста, найдите SO –

+4

Хорошая ссылка на общую площадь. http://rusanu.com/2010/03/26/using-tables-as-queues/ Редактировать: Не уверен, что он отвечает на ваш конкретный вопрос о блокировке до тех пор, пока элементы не будут добавлены в очередь. Также я не уверен, что видел этот конкретный вопрос раньше на SO. –

+2

Вы знаете, что SQL Server имеет * актуальные * очереди, не так ли? http://msdn.microsoft.com/en-us/library/ms345108(v=sql.90).aspx –

ответ

2

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

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

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

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

+0

Спасибо. Это, по сути, обходной путь, который я использую в данный момент, но, как вы полагаете, это не лучшее решение. В частности, я бы предпочел что-то, что не связано с циклом - какая-то операция ожидания, которая либо истекает, либо вводится в действие новой строкой, добавленной в таблицу (через триггер?) – Barguast

1

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

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

+0

По сути, я ищу для лучшего способа передачи рабочих элементов между распределенными службами (в настоящее время на одном компьютере, но в будущем они могут находиться на разных компьютерах в одной локальной сети). В некоторых случаях мне нужен один и тот же рабочий элемент для отправки в две разные очереди, поэтому причина, по которой я изначально решил попробовать свою собственную реализацию. Любые советы будут приветствоваться. На данный момент я рассматриваю комбинацию сервис-брокера, а также набор хранимых процедур, которые будут обрабатывать распределение в несколько очередей. – Barguast

+0

Если природа этих рабочих элементов асинхронна, вы должны рассмотреть что-то вроде MSMQ. MSMQ может обеспечить надежную доставку сообщений через границы обслуживания/машины, включая такие вещи, как переадресация передачи. Но если вы хотите сказать «внутри» SQL Server, Service Broker - именно то, что вы ищете. Каждая служба/машина будет размещать копию SQL Server Express (или лучше), которая будет действовать как локальная очередь. Затем он будет управлять процессом передачи ваших сообщений удаленным службам. Он даже управляет уведомлениями на вашем конце получения сообщения. Он также поддерживает многоадресную рассылку. – RMD

8

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

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

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

+0

Мы используем обычные таблицы SQL в качестве очередей под тяжелыми нагрузками (200K +/hr) и никогда не сталкивались с тупиком. Сама природа структуры очереди поддерживает это, вы вставляете на одном конце (то есть в конец таблицы) и удаляете из другого (т.е. верхнюю часть таблицы через SELECT TOP 1). В реальном мире это сложнее, когда все транзакционно, но это суть этого. – Didaxis

7

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

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

+3

Это отличная статья, хотя по http://stackoverflow.com/a/940001/8479 намеки на блокировку не совсем правильны - например нужен UPDLOCK – Rory

0

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

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

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

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

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

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, который зачисляет транзакции таким образом, назад, если служба завершится неудачей. в этом случае вы захотите пойти с повторными/ядовитыми очередями в виде таблиц в дополнение к вашим очередям.

+0

Является ли этот псевдо-код для вашего слоя приложения? Как вы реализуете GetNextMessage, поэтому несколько работ могут работать над отдельными сообщениями одновременно? Использование блокировки строк?Более подробная информация будет оценена. –

+0

@ Давид, мой последний абзац в моем примере объясняет, как это выполняется. Однако это немного больше связано с тем, что фактические операции с очередями необходимо обрабатывать специально (то есть, если транзакция должна быть откатна, нам все равно нужно, чтобы сообщение переместилось в очереди повтора/яда, если это применимо). GetNextMessage тривиально, работа заставляет SQL делать то, что мы хотим здесь. Вкратце, был использован класс клиента очереди, который обрабатывает завершение транзакции, а SQL SQL CLR была использована на стороне SQL, что позволяет задействовать транзакцию .NET. – Didaxis

Смежные вопросы