|
|
|
Использование функций в запросах
|
|||
|---|---|---|---|
|
#18+
В продолжении темы начатой тут.\r \r Есть запрос, использующий функцию:\r Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. \r Вот от него план:\r Код: plaintext 1. 2. 3. 4. \r Насколько я понял, сначала записи были отобраны по условиям (id_client=3) и только потом была посчитана функция. \r Чем, в таком случае, грозит использование функций?\r \r p.s. ASA9 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.01.2004, 22:08 |
|
||
|
Использование функций в запросах
|
|||
|---|---|---|---|
|
#18+
Здесь ничем :) Действительно функция будет вызвана только на полученные отфильтрованные записи. Однако например, если в функцию вставить какой нибудь SQL запрос, то мы получим вызов этого запроса столько раз, сколько получилось строк после фильтрации основного запроса. В плане запроса естественно такой "подзапрос" обработаться и отобразиться не может, поэтому скорее всего такая уже функция будет тормозить выполнение запроса тем, что постоянно генерить еще запросы, на которые оптимизатору тоже надо строить план запроса и не факт, что он удачно осядет в кэше, плюс на время выполнения таких вот запросиков будут идти постоянные блокировки/разблокировки и т.д. Работы как говориться будет делаться много. Далее еще важный пример : обычная скалярная функция, пусть даже туда параметром передается константа, но участвует такая функция в групповом фильтре: Код: plaintext 1. 2. 3. 4. 5. Здесь сначала будут посчитаны суммы всех групп Id, а потом проведена фильтрация по Id = 100, что не очень приятно и приводит к Table Scan таблицы. Следующий скрипт на пару строчек больше, но выполняется в разы быстрее: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. По плану здесь сначала будете применен фильтр по Id = 100, в том числе по индексу, если Id проиндексированно. Далее уже по полученым записям будут проведены группировки и аггрегирование. Думаю наглядно видно, что здесь функция не очень катит - в первом случае будут последовательно сканиться все записи таблицы, во втором ровно столько, сколько надо. Вообще я бы сказал, что любое использование пользовательских функций для задания связей таблиц, фильтрующих условий, сортировки и т.д. чревато большими тормозами. Это не относиться к системным функциям, которых ASA в состоянии оптимизировать и красиво включить в план запроса. Вот вроде и все мысли по поводу UDF :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.01.2004, 22:44 |
|
||
|
Использование функций в запросах
|
|||
|---|---|---|---|
|
#18+
ASCRUS...В плане запроса естественно такой "подзапрос" обработаться и отобразиться не может, поэтому скорее всего такая уже функция будет тормозить выполнение запроса тем, что постоянно генерить еще запросы, на которые оптимизатору тоже надо строить план запроса и не факт, что он удачно осядет в кэше... часто приходится использовать конструкции: Код: plaintext 1. 2. 3. 4. Разобраться потом (спустя полгода, например) в таком запросе невозможно. К тому же, насколько я понимаю, с (if условие2 then (select ...) else (...) endif) у оптимизатора могут возникнуть те же сложности, что и с функциями. Начал пользоваться фунциями, пока считаю такой подход оправданным. Есть еще одна проблема: есть шапка счета (t_invoice), есть содержание (t_order). Понятно, что постоянно нужна сумма счета. Как быть? Сейчас везде считается подзапросом. Очень хочется иметь сумму без вычислений. Можно в триггере, но иногда необходимо править t_order без триггеров. Плюс, у нас распределенная база (SQL Remote) и без триггеров могут работать админы в филиалах, а сумму хотелось бы иметь корректную. Как быть? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.01.2004, 10:45 |
|
||
|
Использование функций в запросах
|
|||
|---|---|---|---|
|
#18+
Код: plaintext 1. 2. 3. Первый if ничего страшного не делает - это обычное вычислямое поле в запросе. А вот со вторым if Вы конечно погорячились. Если посмотреть план запросов, то будет организовано 2 subquery и они оба будут выполняться, а полученный результат участвовать в фильтре в зависимости от Условия2. Вот такие вещи я и не рекомендую делать - фактически Вы режите работу оптимизатора на корню, на малых обьемах этого не будет заметно, а вот если в таблице миллионы записей, то долгое ожидание выполнения запроса гарантированно. Если у Вас Условие2 статично, то гораздо легче написать вот так: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. План такого запроса будет примитивным и быстрым. Если же у Вас в Условие2 участвуют поля, то однозначно такой запрос вообще надо переписывать по другому или же задуматься об правильности организации структуры БД. Как один из вариантов более легкой для оптимизатора версии запроса: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. Здесь план запроса будет приличным, никаких Subquery и при наличие нужных индексов оптимизатор сможет ими нормально воспользоваться. Я рекомендую себе взять за правило, что конструкция такого типа: Код: plaintext 1. 2. будет всегда медленней работать, чем: Код: plaintext 1. 2. 3. 4. 5. 6. фильтрация по наборам данных с помощью OR всегда медленнее, чем с помощью UNION ALL, и IN во многих случаях может оказаться медленнее, чем INNER JOIN, особенно на больших обьемах данных. авторЕсть еще одна проблема: есть шапка счета (t_invoice), есть содержание (t_order). Понятно, что постоянно нужна сумма счета. Как быть? Сейчас везде считается подзапросом. Очень хочется иметь сумму без вычислений. Можно в триггере, но иногда необходимо править t_order без триггеров. Плюс, у нас распределенная база (SQL Remote) и без триггеров могут работать админы в филиалах, а сумму хотелось бы иметь корректную. Как быть? Если записей в содержании на запись в шапке счета мало, то легче действительно просто считать, скорость при этом не потеряется. Если записей много, то все действительно лучше через триггера - делаете поле TotalSum в t_invoice и при любом добавлении/изменении/удалении записи из t_order просто ее пересчитываете в after триггере на for each statement. Я правда не понял, почему Вы хотите править t_order с отключенными триггерами, но всегда можно сделать глобальную процедуру пересчета итоговых сумм, которая заново рассчитает все итоговые суммы в t_invoice, если они не совпадают с t_order. Как видите из любой ситуации может быть много выходов. Но в РСУБД лучше помнить, что самый красивый по коду и легкий по реализации выход может оказаться на самом деле с точки зрения РСУБД самым кривым и тормознутым. Я бы Вам порекомендовал не пытаться облегчить жизнь себе, как программисту, а в первую очередь думать о самой СУБД, чтобы было удобно ей. Иначе нарветесь на кучу неприятностей. На это я насмотрелся предостаточно, консультируя людей по их БД, которые при больших обьемах данных просто останавливались, повергая их разработчиков в шок, как оказывается они ошибались, используя навороченные запросы, повторно используемый код, оформленный в виде ХП и UDF, структуру таблиц в виде деревьев и т.д. Причем пока данных было мало все работало как часы - быстро и красиво. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.01.2004, 11:51 |
|
||
|
|

start [/forum/topic.php?fid=55&msg=32385349&tid=2014688]: |
0ms |
get settings: |
11ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
167ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
2ms |
| others: | 14ms |
| total: | 287ms |

| 0 / 0 |

Извините, этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
... ля, ля, ля ...