Спасибо за отличную статью, интересует чисто с технической точки зрения, сколько времени вам понадобилось на реализацию такого сложного механизма + эксперименты? Или над этим работала большая команда и они за месяц-два все реализовали, протестировали и выкатили в прод?
Полностью согласен на счет корпоративного почтового сервера, насколько это большое благо я понял только когда пришлось слать почту без него (что и описано выше). «В условиях ограниченных ресурсов» — замечательная формулировка полностью передающая суть описанного в статье, хотя это не домашняя машина.
Раз уж такое дело, то добавлю пару слов о использовании внешних почтовых серверов. Скажем прямо, дело это мутное, в том смысле, что существуют разные ньансы.
Свой код для отправки писем с требующего авторизации почтового сервера привожу ниже. Скажу сразу, что этот код может слать письма в русской кодировке, например на Gmail. Успешность отсылки зависит от принимающего ящика, т.е. если ваше русскоязычное письмо пришло в неподобающем виде — попробуйте поменять строки с кодировкой.
Сам код:
Теперь о ньюансах: их масса, и всех я не знаю, но то с чем столкнулся расскажу:
1. Иногда почта с Yahoo некорректно отображается на Gmail, т.е. я слал одно письмо с Yahoo на 3 разных почтовика, везде все ок, а на Gmail письмо приходит с пустым телом. Почему так — не знаю, но если то же самое письмо отправить с Рамблера, то Gmail его видит отлично.
2. Русский текст. Тут также «темна вода в облацеях» — вы може подобрать параметры, которые будут распознаваться большинством серверов, но на каком-то вы все-равно получите кроказябры. Таким образом идеал — когда вам нужно слать письма только пользователям одного почтового сервера, чтоб вы кастомизировали под него кодировку и тип сообщения (plain/html).
3. Рамблер странный, может мне просто не повезло с временем экспериментов, но суть такова: у меня есть ящик на Рамблере, я протестил указанную выше процедуру — через него она почту шлет отлично. Специально для нужн системы завел новый ящик, и через него почта не пошла: выпадают поочередно ошибки вида «Incorrect username/password» или «Internal server error». Работа с настройками ящиков ни к чему не привела — они одинаковы, возможно, на сервере стоит какой-то таймаут для использования smtp для новых ящиков, хотя звучит это как-то диковато.
На счет отсылки писем из СУБД — не вижу в этом ничего предосудительного (когда, конечно, все происходит в нормально сконфигурированной среде). Просто существует два диаметрально противоположных подхода: БД — только хранилище данных и БД — серверная часть приложения, как правило в живых проектах используется что-то среднее с перекосом в ту или другую сторону.
Если в ваших проектах привыкли не развертывать логику в БД, то да, отсылка оттуда писем, http-запросов и прочий не sql-функционал выглядит неуместно. Если наличие в БД логики для вас норма, все данные находятся и обрабатываются там же, почему бы не отослать письмо с отчетом? Тем более, что это выполняется стандартными средствами, без вызова «external subprograms».
На счет замечаний по моей настройке почты — то все замечания верные, и, в идеальном мире, я бы этим не занимался. Но в реальности бывают разные обстоятельства, разные люди, по-разному выполняющие свою работу. В общем, не займись я этим сам, слал бы я письма руками.
На счет паролей в открытом виде, то в данном случае пароли — не очень критичная информация, в том смысле, что это автоматически сгенерированные пароли для доступа к определенной функциональности в БД (потому их и нужно было рассылать). Хранятся они вместе с той функциональностью, доступ к которой обеспечивают. Другими словами, атака, способная достигнуть таблицы с паролями, равновероятно достигнет и защищаемой ими информации. Поэтому с точки зрения возможности кражи шифровать их бессмысленно, разве что для защиты от передачи по сети в открытом виде. Но тут уже встает вопрос соотношения цены информации к цене ее защиты. С точки зрения критичности такой перехват пароля позволит злоумышленнику всего лишь получить доступ к системе работы с данными, заточенной под весьма специфические операции, а не к самим данным.
Про автоматизированную отсылку через почтовый клиент типа Outlook'a даже не подумал — давно не пользовался, вот специфика мышления и определила однозначное направление поиска решения :)
Ну, скажем откровенно, роль приходящаяся на pls_integer в данном случае столь мала, что оно не повлияет сколь-нибудь существенно :)
Таким образом мы с вами вывели разницу в производительности Оракла в зависимости от машины (я запускал на сервере Intel Xeon 2 ядра по 3Ghz, 4 Gb RAM), который в тот момент был ничем не загружен.
У меня когда-то на ноутбуке Оракл стоял для домашних целей (AMD Turion 2 Ghz и 512 RAM), так ничего, работал, правда грузился долго. Но вот когда вместе с ним запустить NetBeans, например, то все жутко тормозило из-за нехватки памяти.
Пока писал, вспомнил, что у меня есть старая машина Athlon 1,41 Ghz, 256 RAM. Запустил запрос на ней, время выполнения 14 сек.
Спасибо, повеселили :)
Анонимный блок для Оракл (проверял, выполняется приблизительно одинаково с хранимой процедурой):
declare
U number:=1;
S number:=1;
I pls_integer:=3;
begin
WHILE (abs(U) >= 0.0000001) loop
U:= -U*1*1*(I-2)/I;
S:= S + U;
I:= I + 2;
END loop;
dbms_output.put_line(4*S);
end;
Время выполнения около 4.5 сек.
Конечно, нужно на одинаковых машинах скорость замерять.
Да, спасибо за идею, добавил раздел «Особенности отображения дат в различных приложениях».
Имхо, для задания единого формата дат для всех сессий удобнее всего использовать ON_LOGON триггер, предложенный Томом, с указанием своего формата.
Явное указание масок для to_date и to_char, конечно, самый надежный вариант, но триггер тоже может обеспечить достаточную степень надежности (если никто сам не будет делать ALTER SESSION :)).
Да, действительно, фраза про union написана так, что может быть прочитана двояко. Я имел ввиду механику работы union, когда для построения объединения множеств они вначале сортируются, и не подразумевал, что union может вернуть отсортированный результат и заменить таким образом order by.
Про «union all гарантирует сохранение исходного порядка строк» я имел ввиду, что при объединении множества А с множеством В в результирующей выборке будут идти сначала строки из множества А, потом из множества В. Сам порядок выдачи строк начиная то ли с 10-ки, то ли даже раньше, Оракл не гарантирует (из обычного select), что уж говорить про union all.
Поскольку в примере, к которому относится эта фраза, каждое множество было представлено одной строкой, то union all гарантировал сохранение этого порядка строк :) В общем, тоже весьма двояко написал, впредь постараюсь точнее излагать.
Бывают разные специфические требования к порядку строк и выдаче данных. Предположим, что мы составляем отчет по клиентам, в отчете должно быть только ФИО и дата начала обслуживания, а отсортировать их нужно по «толщине кошелька», чтоб руководство сразу видело, кто им больше люб. «Толщина кошелька» вычисляется по нескольким полям с помощью формулы.
Тогда вы либо вводите «толщину кошелька» как еще одно поле в select и потом из полученных данных делаете еще одну выборку уже без этого поля (т.е. как писали выше, получаете дополнительный уровень вложенности), либо сразу используете формулу в order by.
На самом деле всяко бывает, например, может сложиться ситуация, когда ФИО целиком лежит в одной колонке и его нужно вывести, а сортировка должна быть по имени. Тогда вы в order by используете substr, не забивая результирующую выборку ненужным полем с именем.
Раз уж такое дело, то добавлю пару слов о использовании внешних почтовых серверов. Скажем прямо, дело это мутное, в том смысле, что существуют разные ньансы.
Свой код для отправки писем с требующего авторизации почтового сервера привожу ниже. Скажу сразу, что этот код может слать письма в русской кодировке, например на Gmail. Успешность отсылки зависит от принимающего ящика, т.е. если ваше русскоязычное письмо пришло в неподобающем виде — попробуйте поменять строки с кодировкой.
Сам код:
Этот код у меня успешно слал письма с Рамблера и Yahoo. Вызов происходит так:
Теперь о ньюансах: их масса, и всех я не знаю, но то с чем столкнулся расскажу:
1. Иногда почта с Yahoo некорректно отображается на Gmail, т.е. я слал одно письмо с Yahoo на 3 разных почтовика, везде все ок, а на Gmail письмо приходит с пустым телом. Почему так — не знаю, но если то же самое письмо отправить с Рамблера, то Gmail его видит отлично.
2. Русский текст. Тут также «темна вода в облацеях» — вы може подобрать параметры, которые будут распознаваться большинством серверов, но на каком-то вы все-равно получите кроказябры. Таким образом идеал — когда вам нужно слать письма только пользователям одного почтового сервера, чтоб вы кастомизировали под него кодировку и тип сообщения (plain/html).
3. Рамблер странный, может мне просто не повезло с временем экспериментов, но суть такова: у меня есть ящик на Рамблере, я протестил указанную выше процедуру — через него она почту шлет отлично. Специально для нужн системы завел новый ящик, и через него почта не пошла: выпадают поочередно ошибки вида «Incorrect username/password» или «Internal server error». Работа с настройками ящиков ни к чему не привела — они одинаковы, возможно, на сервере стоит какой-то таймаут для использования smtp для новых ящиков, хотя звучит это как-то диковато.
Если в ваших проектах привыкли не развертывать логику в БД, то да, отсылка оттуда писем, http-запросов и прочий не sql-функционал выглядит неуместно. Если наличие в БД логики для вас норма, все данные находятся и обрабатываются там же, почему бы не отослать письмо с отчетом? Тем более, что это выполняется стандартными средствами, без вызова «external subprograms».
На счет замечаний по моей настройке почты — то все замечания верные, и, в идеальном мире, я бы этим не занимался. Но в реальности бывают разные обстоятельства, разные люди, по-разному выполняющие свою работу. В общем, не займись я этим сам, слал бы я письма руками.
На счет паролей в открытом виде, то в данном случае пароли — не очень критичная информация, в том смысле, что это автоматически сгенерированные пароли для доступа к определенной функциональности в БД (потому их и нужно было рассылать). Хранятся они вместе с той функциональностью, доступ к которой обеспечивают. Другими словами, атака, способная достигнуть таблицы с паролями, равновероятно достигнет и защищаемой ими информации. Поэтому с точки зрения возможности кражи шифровать их бессмысленно, разве что для защиты от передачи по сети в открытом виде. Но тут уже встает вопрос соотношения цены информации к цене ее защиты. С точки зрения критичности такой перехват пароля позволит злоумышленнику всего лишь получить доступ к системе работы с данными, заточенной под весьма специфические операции, а не к самим данным.
Про автоматизированную отсылку через почтовый клиент типа Outlook'a даже не подумал — давно не пользовался, вот специфика мышления и определила однозначное направление поиска решения :)
Таким образом мы с вами вывели разницу в производительности Оракла в зависимости от машины (я запускал на сервере Intel Xeon 2 ядра по 3Ghz, 4 Gb RAM), который в тот момент был ничем не загружен.
У меня когда-то на ноутбуке Оракл стоял для домашних целей (AMD Turion 2 Ghz и 512 RAM), так ничего, работал, правда грузился долго. Но вот когда вместе с ним запустить NetBeans, например, то все жутко тормозило из-за нехватки памяти.
Пока писал, вспомнил, что у меня есть старая машина Athlon 1,41 Ghz, 256 RAM. Запустил запрос на ней, время выполнения 14 сек.
Анонимный блок для Оракл (проверял, выполняется приблизительно одинаково с хранимой процедурой):
Время выполнения около 4.5 сек.
Конечно, нужно на одинаковых машинах скорость замерять.
Имхо, для задания единого формата дат для всех сессий удобнее всего использовать ON_LOGON триггер, предложенный Томом, с указанием своего формата.
Явное указание масок для to_date и to_char, конечно, самый надежный вариант, но триггер тоже может обеспечить достаточную степень надежности (если никто сам не будет делать ALTER SESSION :)).
Про «union all гарантирует сохранение исходного порядка строк» я имел ввиду, что при объединении множества А с множеством В в результирующей выборке будут идти сначала строки из множества А, потом из множества В. Сам порядок выдачи строк начиная то ли с 10-ки, то ли даже раньше, Оракл не гарантирует (из обычного select), что уж говорить про union all.
Поскольку в примере, к которому относится эта фраза, каждое множество было представлено одной строкой, то union all гарантировал сохранение этого порядка строк :) В общем, тоже весьма двояко написал, впредь постараюсь точнее излагать.
Тогда вы либо вводите «толщину кошелька» как еще одно поле в select и потом из полученных данных делаете еще одну выборку уже без этого поля (т.е. как писали выше, получаете дополнительный уровень вложенности), либо сразу используете формулу в order by.
На самом деле всяко бывает, например, может сложиться ситуация, когда ФИО целиком лежит в одной колонке и его нужно вывести, а сортировка должна быть по имени. Тогда вы в order by используете substr, не забивая результирующую выборку ненужным полем с именем.
Обычно либо в условиях:
Либо, что более полезно, для обработки данных из вложенных подзапросов: