ProgramaciónDesarrollador Backend

¿Cómo implementar reglas de negocio complejas y cálculos directamente en SQL utilizando funciones definidas por el usuario (User Defined Functions, UDF)? ¿Cuáles son las diferencias y limitaciones entre UDF escalares y tabulares, cuándo es apropiado aplicarlos y cuándo es mejor implementar dicha lógica en una aplicación externa?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En SQL se puede implementar la lógica de negocio a través de funciones definidas por el usuario (User Defined Functions, UDF), lo que permite trasladar parte de los cálculos y reglas de negocio a la base de datos.

Funciones escalares devuelven un único valor y se llaman en expresiones; por ejemplo, para calcular un total basado en parámetros:

CREATE FUNCTION dbo.GetDiscount(@price DECIMAL(10,2), @loyaltyLevel INT) RETURNS DECIMAL(10,2) AS BEGIN RETURN @price * CASE WHEN @loyaltyLevel = 1 THEN 0.95 WHEN @loyaltyLevel = 2 THEN 0.90 ELSE 1.0 END END; -- Ejemplo de uso: SELECT Name, dbo.GetDiscount(Price, LoyaltyLevel) AS DiscountPrice FROM Products;

Funciones tabulares devuelven un conjunto de filas (una tabla):

CREATE FUNCTION dbo.ActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Uso: SELECT * FROM dbo.ActiveOrders(123);

Diferencias, limitaciones y recomendaciones:

  • UDF escalares a menudo tienen un bajo rendimiento en grandes conjuntos de datos, ya que se llaman fila por fila;
  • UDF tabulares se integran mejor en los planes de consulta y permiten ser usados como tablas ordinarias;
  • La lógica que requiere acceso a recursos externos o un procesamiento de negocio complejo es mejor sacarla fuera de SQL.

Pregunta engañosa.

¿Cuál es la diferencia entre una función tabular INLINE y una función tabular multi-instrucción (multi-statement)? ¿Cómo afecta esta elección al rendimiento?

Respuesta y ejemplo:

  • La función INLINE (de una única instrucción, devuelve un SELECT directamente) se optimiza como parte de la consulta principal, no crea una tabla adicional y funciona más rápido, el plan de consulta es común.
  • La función multi-instrucción crea una tabla temporal (variable de tabla), lo que generalmente resulta en un peor plan de consulta, es posible que haya errores en la estimación de cardinalidad y disminución en el rendimiento.
-- INLINE CREATE FUNCTION dbo.InlineActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Multi-instrucción CREATE FUNCTION dbo.MultiActiveOrders(@userId INT) RETURNS @result TABLE (...) AS BEGIN INSERT INTO @result SELECT ... -- lógica RETURN END

Historia

Proyecto: Análisis Financiero. Utilizamos UDF escalares en la parte SELECT de una consulta de informe a un gran conjunto de tablas: SELECT Amount, dbo.CalcTax(Amount, Type) FROM Transactions. La consulta tardaba de 5 a 10 minutos debido al procesamiento fila por fila de las UDF. Se reescribió utilizando CASE incorporado: el tiempo se redujo a segundos.


Historia

Proyecto: E-commerce. Para buscar los carritos de los usuarios utilizamos funciones tabulares multi-instrucción, donde había lógica de filtrado en varios pasos. Resultó que SQL no creaba un plan óptimo y realizaba un escaneo, incluso cuando se necesitaba un solo elemento. El cambio a una función INLINE aceleró las consultas 50 veces de inmediato.


Historia

Proyecto: CRM. Extrajimos la lógica de negocio para la asignación de bonificaciones a una UDF compleja. Después de un par de meses, nos dimos cuenta de que las fórmulas del negocio habían cambiado y que actualizar la función era complicado debido a la rígida vinculación con los datos. En un producto iterativo, la UDF resultó en altos costos de coordinación de cambios entre el back-end y la base de datos.