29 июн. 2011 г.

Trigger vs Change Notification

На днях, общаясь с заказчиком, я столкнулся с одной очень распространненой задачей: в существующем приложении (реализовано на PL/SQL+APEX), при изменении статуса документа необходимо отправлять письмо-нотификацию по электронной почте.Заказчик намеревался написать для этого очередной триггер и "повесить" его на табличку с документами.

У меня сразу же возникли два возражения:
1) Отправка нотификации это внешний сервис, то есть НЕ является составной частью жизненного цикла документа.
2) Отработка триггера будет замедлять работу приложения сервисной операцией.

Для решения этой задачи есть более подходящий, на мой взгляд, способ - использовать технологию Database Change Notification.
Эта технология позволяет подписаться на сообщение об изменение данных, и получив это уведомление, выполнить некоторую обработку. Возможен вариант обработки как на сервере (в виде PL/SQL-процедуры), либо на клиенте - в виде callback-процедуры на клиенте.

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

Собственно как это делается.
На первом шаге пользователю нужно дать две привилегии:
1) на сервисный системный пакет dbms_cq_notification -
grant execute on dbms_cq_notification to rscott;

2) собственно права на получение нотификации об изменениях -
grant change notification to rscott;

После этого нужно создать PL/SQL-процедуру, которая автоматическм будет "зажигаться" при изменении данных.
--процедура обработки в виде статического метода объектного типа:
  static procedure StateChangeHandler(ntfnds in cq_notification$_descriptor) is
    v_xNumRows        number;
    v_xOperationType  number;
    v_xRowIdStr       varchar2(2000 char);
    v_xRowId          rowid;
    v_xDocument       TDocumentOfRegistration;
  begin
    if (ntfnds.event_type = dbms_cq_notification.event_querychange) then
      v_xOperationType := ntfnds.query_desc_array(1).table_desc_array(1).Opflags;

      --реагируем только на операции UPDATE
      if v_xOperationType = dbms_cq_notification.UpdateOp then
      
        if (bitand(v_xOperationType, dbms_cq_notification.all_rows) = 0) then
          --определяем количество строк которые затронули изменения в родительской транзакции
          v_xNumRows := ntfnds.query_desc_array(1).table_desc_array(1).numrows;
          
          for k in 1..v_xNumRows 
          loop 
            --извлекаем rowid строк, которые изменились
            v_xRowIdStr := ntfnds.query_desc_array(1).table_desc_array(1).row_desc_array(k).row_id;
            v_xRowId    := chartorowid(v_xRowIdStr);
            
            --читаем документ:
            v_xDocument := new TDocumentOfRegistration(v_xRowId); 
              
            --отправляем письмо по email об изменении:
            v_xDocument.sendStateChangeLetter();

            v_xDocument.destroy;
          end loop;
        end if;
      end if;
    end if;

    commit;
  end;

Наконец, регистрируем наш обработчик:
declare
  v_xRegInfo          cq_notification$_reg_info;
  v_xNotificationQoS  simple_integer    := dbms_cq_notification.qos_query +
                                           dbms_cq_notification.qos_rowids;
  v_xCallback         varchar2(64 char) := 'rscott.TDocumentOfRegistration.StateChangeHandler';
  v_xCursor           sys_refcursor;
  v_xRegId            number;
begin
  v_xRegInfo := new cq_notification$_reg_info(callback          => v_xCallback,
                                              qosflags          => v_xNotificationQoS,
--нотификация посылается для всех операций
                                              operations_filter => 0, 
--регистрация существует вечно, до тех пока явно не будет удалена
                                              timeout           => 0, 
--нотификация посылается немедленно после фиксации транзакции
                                              transaction_lag   => 0);
  v_xRegId := dbms_cq_notification.new_reg_start(v_xRegInfo);

  open v_xCursor for 
    select 
      Id 
    from 
      documents 
    where 
      State = 'ACTIVE';

  close v_xCursor;

  dbms_cq_notification.reg_end;
end;
/

Как Вы видите, наш обработчик будет вызываться только если изменение затронуло документы находящиеся в состоянии 'ACTIVE'.

В заключение, небольшой FAQ.
1) Вопрос: требуется ли дополнительная настройка для работы Database Change Notification ?
Ответ: Необходимо лишь установить в ненулевое значение параметр job_queue_processes.

2) Вопрос: Если транзакция, в которой генерировались изменения, была незавершена (например был явный rollback) ?
Ответ: В этом случае никакого сообщения отправлено НЕ будет - нотификация отправляется только после фиксации транзакции.

3) Вопрос: Я искал в документации описание этой технологии, но никак не могу найти.
Ответ: Описание технологии Database Change Notification "запрятано" в Oracle Database Advanced Developet Guide

4) Вопрос: Правильно ли я понял, что подписка происходит на изменение результатов запроса, а не всей таблицы в целом.
Ответ: Именно так! Хотя при регистрации можете указать, что Вас интересует изменение всей таблицы в целом.

20 июн. 2011 г.

Новые правила лицензирования Oracle Database в Amazon Cloud

Компания Amazon – наиболее известный и крупный Cloud провайдер в мире. До недавних пор, пользователи или компании, кто размещал свои решения (Oracle Database), должны были покупать лицензии самостоятельно через партнеров или напрямую у Oracle. Теперь, стало возможно лицензирование Oracle Database с тарификацией по часам в Amazon Cloud.
Полный текст статьи здесь: http://aws.amazon.com/rds/oracle/?ref_=pe_8050_20231810

Сейчас поддерживается две модели лицензирования: “License Included” and “Bring-Your-Own-License (BYOL)”. Первая модель, она же новая, включает в себя лицензии на ПО Oracle. Например, для Oracle Database Standard Edition One в конфигурации Small нужно платить 0,16 центов в час за предоставленную виртуальную машину(On-Demand DB Instance). При наличии уже купленных лицензий, метод BYOL, стоимость будет 0,11 в час для той же конфигурации виртуальной машины. Также существует возможность оплатить и первый и второй вариант за 1-2-3 лет, что существенно выгоднее по деньгам.

Oracle Database Editions, что важно, цитата:
Amazon RDS currently supports multiple Oracle Database Editions. Support for a given edition varies by licensing model. See pricing for more information on the licensing models offered by Amazon RDS for Oracle:

  • Standard Edition One: License Included, Bring-Your-Own License
  • Standard Edition: Bring-Your-Own-License
  • Enterprise Edition: Bring-Your-Own-License

Т.е. Amazon берет на себя обязательство и предоставляет сервис с лицензиями Oracle DB только для редакции Oracle Database Standard Edition One!!! Это важно.

Далее я попытался понять, а сколько будут стоить лицензии Oracle DB SE One за один год аренды.

Конфигурация SMALL Reserved DB Instances:
345$-227.50$ = 117,5$
*Small DB Instance: 1.7 GB memory, 1 ECU (1 virtual core with 1 ECU), 64-bit platform, Moderate I/O Capacity

Конфигурация Extra Large (High Memory) DB Instances:
1,850$ - 1,325$ = 525$
*High-Memory Extra Large Instance 17.1 GB memory, 6.5 ECU (2 virtual cores with 3.25 ECUs each), 64-bit platform, High I/O Capacity

С виду, размещение в Amazon Cloud выглядит заманчиво, но не стоит забывать про дополнительные затраты, за которые также придется заплатить: трафик, I/O, …

Для кого это полезно:
• Для стартап проектов, когда неизвестно, сколько по времени проект буде существовать
• Для разработчиков - проведение нагрузочного испытания или тестирования системы
• Для администраторов, если нужно собрать стенд из нескольких серверов
• Для небольших компаний – Small Business
• Для защиты данных ЦОД от катастроф
• И т.д.

CLOUD наступает!