Я использую SQL UDF для инкапсуляции простой отчетности / бизнес-логики. Должен ли я избежать этого? - PullRequest
7 голосов
/ 29 января 2010

Я создаю новую базу данных в SQL Server 2008 для некоторых отчетов, и есть много общих бизнес-правил, касающихся этих данных, которые входят в различные типы отчетов. В настоящее время эти правила в основном объединены в более крупных процедурных программах на унаследованном языке, который я пытаюсь перенести на SQL. Я стремлюсь к гибкости в реализации отчетов по этим данным, например, в SAS, в C # и т. Д.

В настоящее время мой подход состоит в том, чтобы разбить эти общие правила (обычно ОЧЕНЬ простую логику) и инкапсулировать их в отдельные пользовательские функции SQL. Производительность не имеет значения, я просто хочу использовать эти правила для заполнения статических полей в виде своего рода «снимка» отчета, который затем можно использовать для создания отчетов любым удобным для вас способом.

Мне нравится этот модульный подход, поскольку я понимаю, что делает каждое правило (и поддерживает сами правила), но я также начинаю немного бояться, что обслуживание также может стать кошмаром. Некоторые правила зависят от других, но я не могу уйти от этого - эти вещи строятся друг на друге ... чего я хочу ... я думаю? ;)

Существуют ли лучшие подходы для этого модульного подхода в базе данных? Я на правильном пути, или я думаю об этом слишком много в мышлении разработки приложений?

Ответы [ 5 ]

2 голосов
/ 29 января 2010

Сохранение логики на стороне базы данных - почти всегда правильное решение.

Как вы упомянули в своем вопросе, большинство бизнес-правил включают в себя довольно простую логику, но обычно они работают с огромными объемами данных.

Механизм базы данных - это то, что нужно для реализации этой логики, потому что, во-первых, он сводит данные I/O к минимуму, а во-вторых, база данных выполняет преобразования данных гораздо эффективнее.

Некоторое время назад я написал очень субъективное сообщение в блоге на эту тему:

Примечание с одной стороны: UDF - это не то же самое, что хранимая процедура.

A UDF - это функция, разработанная для вызова внутри запроса, поэтому она может выполнять только очень ограниченное подмножество возможных операций.

Вы можете сделать гораздо больше - это хранимая процедура.

Обновление:

В приведенном вами примере, например, при смене логики, которая вычисляет «производное поле», UDF, которая вычисляет поле, в порядке.

Но (на всякий случай), когда производительность будет проблемой (и поверьте мне, это будет гораздо раньше, чем можно подумать), преобразование данных с помощью операций на основе множеств может быть гораздо более эффективным, чем использование UDF s.

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

Один пример: у вашего запроса есть что-то вроде «пользовательского балла», который, по вашему мнению, может быть изменен, и оберните его в UDF

SELECT  user_id, fn_getUserScore(user_id)
FROM    users

Изначально это просто простое поле в таблице:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT
AS
BEGIN
        DECLARE @ret INT
        SELECT  user_score
        INTO    @ret
        FROM    users
        WHERE   user_id = @user_id
        RETURN @ret
END

, тогда вы решаете рассчитать его, используя данные из другой таблицы:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT
AS
BEGIN
        DECLARE @ret INT
        SELECT  SUM(vote)
        INTO    @ret
        FROM    user_votes
        WHERE   user_id = @user_id
        RETURN @ret
END

В этом случае двигатель будет использовать наименее эффективный алгоритм NESTED LOOPS в любом случае.

Но если вы создали представление и переписали базовые запросы следующим образом:

SELECT  user_id, user_score
FROM    users

SELECT  user_id, SUM(vote) AS user_score
FROM    users u
LEFT JOIN
        user_votes uv
ON uv.user_id = u.user_id

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

2 голосов
/ 29 января 2010

В какой-то момент широкое использование UDF начнет вызывать проблемы с производительностью, так как они выполняются для каждой строки в вашем наборе результатов и неясной логике из оптимизатора, затрудняя использование индексов (то есть я не очень понимаю, как производительность не может быть проблемой, но вы знаете свои требования лучше всего). Для определенной функциональности они великолепны; но используйте их экономно.

1 голос
/ 29 января 2010

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

Использование нескольких функций говорит мне, что модель данных была сделана очень "гибкой". Для меня это означает сомнительную типизацию данных и общее определение столбца / таблицы. Существует необходимость в функциях / и т. Д., Потому что база данных позволит хранить что угодно, что означает, что вероятность плохих данных очень высока. Я бы предпочел приложить усилия, чтобы всегда иметь хорошие / действительные данные, а не работать после факта, чтобы бороться с существующими плохими данными.

База данных - это место для хранения этой логики. Это быстрее, чем код приложения, и что самое важное - централизовано, чтобы минимизировать поддержку.

1 голос
/ 29 января 2010

Я бы сказал, что вы на правильном пути - процедуры sql могут быстро выйти из-под контроля, поскольку все более и более сложные и инкапсулирующие разделяемые повторяющиеся фрагменты логики в UDF - совершенно подходящее решение для решения этой проблемы.

Я часто захожу настолько далеко, что инкапсулирую логику из процедуры sql, которая используется только в этой одной процедуре, в хорошо названную UDF для улучшения читабельности.

Посмотрите эту статью MSDN в UDF - возможно, это даст вам больше идей об их использовании?

Существуют различные соображения производительности, о которых вам нужно знать, если вы собираетесь интенсивно использовать UDF - такие вещи, как производительностьскалярные и табличные пользовательские функции и возможные преимущества пользовательских функций CLR.

0 голосов
/ 29 января 2010

Если вы заинтересованы в создании хранилища данных для создания отчетов, вы бы постарались включить как можно больше этого в часть преобразования ETL, чтобы ваш SQL для отчетов состоял из простых операторов, которые способны генерировать как инструменты, так и пользователи.

SSIS - очень эффективный инструмент ETL, который поставляется с сервером SQL для такого рода вещей.

...