2013-04-16 3 views
1

AQ $ _MESSAGES_EXCEPTIONПрежде всего, я знаю, что есть этот вопрос: How to clear a queue in Oracle AQ, но у него нет ответа.Есть ли быстрый способ очистки очереди Exception от Oracle AQ?

У меня много сообщений (500k) в очереди исключений в Oracle AQ (я не знал, что истекшие сообщения перемещаются в другую очередь, поэтому я не создал для них пользователя). Теперь мне нужно иметь возможность быстро удалять эти сообщения. Я читал, что не удастся очистить таблицу очередей с помощью delete, потому что это может привести к несогласованному состоянию. Таким образом, я соединил следующие процедуры, но только очищает около 50 сообщений/секунду

EXECUTE dbms_aqadm.start_queue(queue_name => 'AQ$_MESSAGES_EXCEPTION', 
           enqueue => FALSE, dequeue => TRUE); 

DECLARE 
    dequeue_options  DBMS_AQ.dequeue_options_t; 
    message_properties DBMS_AQ.message_properties_t; 
    message_handle  RAW(16); 
    message    SYS.AQ$_JMS_MESSAGE; 
    no_messages   EXCEPTION; 
    pragma exception_init (no_messages, -25228); 
BEGIN 
    dequeue_options.wait := DBMS_AQ.NO_WAIT; 
    dequeue_options.navigation := DBMS_AQ.FIRST_MESSAGE; 
    LOOP 
    DBMS_AQ.DEQUEUE(
     queue_name   =>  'AQ$_MESSAGES_EXCEPTION', 
     dequeue_options  =>  dequeue_options, 
     message_properties =>  message_properties, 
     payload    =>  message, 
     msgid    =>  message_handle); 
    DBMS_OUTPUT.put_line ('Message: ' || message_handle || ' dequeued'); 
    END LOOP; 
    EXCEPTION 
    WHEN no_messages THEN 
     DBMS_OUTPUT.put_line (' ---- NO MORE MESSAGES ---- '); 
    WHEN others then 
     DBMS_OUTPUT.put_line ('Exception queue not started for dequeue.'); 
END; 

/

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

EDIT:

Я попытался dequeue_array по ссылке здесь: http://www.oracle-developer.net/display.php?id=319 Но я не могу создать таблицы, так что я пытаюсь создать массив в «магазин» результаты. Вот что я получил:

DECLARE 
    type messages_type is varray(500) of SYS.AQ$_JMS_MESSAGE; 
    messages   messages_type; 
    dequeue_options  DBMS_AQ.dequeue_options_t; 
    msg_properties  DBMS_AQ.message_properties_array_t; 
    msg_ids    DBMS_AQ.MSGID_ARRAY_T; 
    x_timeout   EXCEPTION; 
    no_messages   EXCEPTION; 
    dequeue_batch  PLS_INTEGER := 500; 
    pragma exception_init (no_messages, -25228); 
BEGIN   
    messages := messages_type(); 
    msg_properties := DBMS_AQ.MESSAGE_PROPERTIES_ARRAY_T(); 
    msg_properties.EXTEND(dequeue_batch);  
    msg_ids := DBMS_AQ.MSGID_ARRAY_T(); 
    dequeue_options.wait := 5; 
LOOP 
    DBMS_AQ.DEQUEUE_ARRAY(
    queue_name   =>  'AQ$_MESSAGES_EXCEPTION', 
    dequeue_options  =>  dequeue_options, 
    array_size   =>  dequeue_batch, 
    message_properties_array =>  msg_properties, 
    payload_array    =>  messages, 
    msgid_array    =>  msg_ids); 
... 

Я получаю эту ошибку:

wrong number or types of arguments in call to 'DEQUEUE_ARRAY' 

Я думаю, что проблема в массиве сообщений, но я не знаю, что делать, чтобы сделать он работает. Кроме того, в соответствии с оракулом документ (http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_aq.htm#i1000850), должен быть еще один параметр:

error_array    OUT error_array_t 

Но объяснение для этого параметра «В настоящее время не реализован». Что это значит? Можно ли это оставить? Должно ли оно быть нулевым? Это действительно сбивает с толку и Google здесь не поможет :(

ответ

2

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

но ссылка вы предоставляете действительно есть решение:

-- purge queue 
DECLARE 
po_t dbms_aqadm.aq$_purge_options_t; 
BEGIN 
    dbms_aqadm.purge_queue_table('MY_QUEUE_TABLE', NULL, po_t); 
END; 

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

BEGIN 
    DBMS_AQADM.STOP_QUEUE(
    queue_name => 'demo_queue' 
    ); 
    DBMS_AQADM.DROP_QUEUE(
    queue_name => 'demo_queue' 
    ); 
    DBMS_AQADM.DROP_QUEUE_TABLE(
    queue_table => 'demo_queue_table' 
    ); 
END; 
+0

Но проблема в том, что в очереди исключений нет отдельной таблицы. Поэтому, если бы я использовал решение из ссылки, я бы также удалял данные из обычной очереди, и я не хочу этого. Я попробую массив dequeue и посмотрю, будет ли он быстрее. – NeplatnyUdaj

+0

Я сдаюсь. Я не могу собрать процедуру для вызова dequeue_array. – NeplatnyUdaj

+0

Я вижу, я делаю это из .NET-кода, и я не сталкивался с какой-либо проблемой. библиотека Oracle предоставляет API для очередей. У вас есть это: http://www.oracle-developer.net/display.php?id=319 –

1

Вы можете использовать процедуру «purge_queue_table» (как сказал @Stephane) из dbms_aqadm пакета , но с параметром «purge_condition» указано, с помощью этого параметра вы можете выбрать, какие сообщения вы удаляете:

Пример:

declare 

    purge_options dbms_aqadm.aq$_purge_options_t; 

begin 

     purge_options.block := false; 

     purge_options.delivery_mode := dbms_aqadm.persistent; 

     dbms_aqadm.purge_queue_table 
     (queue_table  => 'vista.svig_std_tab', 
      purge_condition => 'qtview.queue = ''AQ$_SVIG_STD_TAB_E'' and qtview.enq_time < to_date(''01.06.2014 00:00:00'',''dd.mm.yyyy hh24:mi:ss'') ', 
      purge_options => purge_options 
     ); 

end; 
/

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

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