Сохранение логики на стороне базы данных - почти всегда правильное решение.
Как вы упомянули в своем вопросе, большинство бизнес-правил включают в себя довольно простую логику, но обычно они работают с огромными объемами данных.
Механизм базы данных - это то, что нужно для реализации этой логики, потому что, во-первых, он сводит данные 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
, это дало бы движку гораздо более широкое пространство для оптимизации при сохранении структуры набора результатов и отделения логики от представления.