Si.
No especificar WITH SCHEMABINDING
significa que SQL Server omite las verificaciones detalladas que normalmente realiza en el cuerpo de la función. Simplemente marca la función como datos de acceso (como se menciona en el enlace dado en la pregunta).
Esta es una optimización de rendimiento. Si no hizo esta suposición, SQL Server tendría que realizar las verificaciones detalladas de cada invocación de función (ya que la función independiente podría cambiar en cualquier momento).
Hay cinco propiedades de función importantes:
- Determinismo
- Precisión
- Acceso a los datos
- Acceso a datos del sistema
- Verificación del sistema
Por ejemplo, tome la siguiente función escalar independiente:
CREATE FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
AS
BEGIN
RETURN '19000101';
END;
Podemos mirar las cinco propiedades usando una función de metadatos:
SELECT
IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);
Las dos propiedades de acceso a datos se han establecido como verdaderas y las otras tres se han establecido como falsas .
Esto tiene implicaciones más allá de las que podrían esperarse (uso en vistas indexadas o columnas calculadas indexadas, por ejemplo).
Efectos en el optimizador de consultas
La propiedad de determinismo en particular afecta al optimizador de consultas. Tiene reglas detalladas sobre los tipos de reescrituras y manipulaciones que puede realizar, y estas están muy restringidas para elementos no deterministas. Los efectos secundarios pueden ser bastante sutiles.
Por ejemplo, considere las siguientes dos tablas:
CREATE TABLE dbo.T1
(
SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
SomeDate datetime PRIMARY KEY
);
... y una consulta que usa la función (como se definió anteriormente):
SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = dbo.F(T1.SomeInteger);
El plan de consulta es el esperado, con una búsqueda en la tabla T2:
Sin embargo, si la misma consulta lógica se escribe utilizando una tabla derivada o una expresión de tabla común:
WITH CTE AS
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
)
SELECT *
FROM CTE
JOIN dbo.T2 AS T2
ON T2.SomeDate = CTE.dt;
-- Derived table
SELECT
*
FROM
(
SELECT *, dt = dbo.F(T1.SomeInteger)
FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = T1.dt;
El plan de ejecución ahora presenta una exploración, con el predicado que involucra la función atascada en un filtro:
Esto también sucede si la tabla derivada o la expresión de tabla común se reemplaza por una vista o una función en línea. Una FORCESEEK
pista (y otros intentos similares) no tendrá éxito:
El problema fundamental es que el optimizador de consultas no puede reordenar elementos de consulta no deterministas tan libremente .
Para producir una búsqueda, el predicado de filtro necesitaría moverse hacia abajo del plan al acceso de datos T2. Este movimiento se evita cuando la función no es determinista.
Reparar
La solución para este ejemplo implica dos pasos:
- Añadir
WITH SCHEMABINDING
- Hacer la función determinista
El primer paso es trivial. El segundo implica eliminar la conversión implícita no determinista de la cadena a datetime
; reemplazándolo con un determinista CONVERT
. Ninguno de los dos es suficiente por sí solo .
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CONVERT(datetime, '19000101', 112);
END;
Las propiedades de la función son ahora:
Con el optimizador liberado, todos los ejemplos ahora producen el plan de búsqueda deseado .
Tenga en cuenta que el uso de CAST
a datetime
en la función no funcionaría, porque no es posible especificar un estilo de conversión en esa sintaxis:
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CAST('19000101' AS datetime);
END;
Esta definición de función produce el plan de exploración, y las propiedades muestran que sigue siendo no determinista: