Algunos ejemplos para mostrar, por si acaso:
Tabla en línea valorada
CREATE FUNCTION MyNS.GetUnshippedOrders()
RETURNS TABLE
AS
RETURN SELECT a.SaleId, a.CustomerID, b.Qty
FROM Sales.Sales a INNER JOIN Sales.SaleDetail b
ON a.SaleId = b.SaleId
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.ShipDate IS NULL
GO
Tabla de declaración múltiple valorada
CREATE FUNCTION MyNS.GetLastShipped(@CustomerID INT)
RETURNS @CustomerOrder TABLE
(SaleOrderID INT NOT NULL,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
OrderQty INT NOT NULL)
AS
BEGIN
DECLARE @MaxDate DATETIME
SELECT @MaxDate = MAX(OrderDate)
FROM Sales.SalesOrderHeader
WHERE CustomerID = @CustomerID
INSERT @CustomerOrder
SELECT a.SalesOrderID, a.CustomerID, a.OrderDate, b.OrderQty
FROM Sales.SalesOrderHeader a INNER JOIN Sales.SalesOrderHeader b
ON a.SalesOrderID = b.SalesOrderID
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.OrderDate = @MaxDate
AND a.CustomerID = @CustomerID
RETURN
END
GO
¿Hay alguna ventaja de usar un tipo (en línea o declaración múltiple) sobre el otro? ¿Hay ciertos escenarios cuando uno es mejor que el otro o las diferencias son puramente sintácticas? Me doy cuenta de que las dos consultas de ejemplo están haciendo cosas diferentes, pero ¿hay alguna razón por la que las escribiría de esa manera?
Leer sobre ellos y las ventajas / diferencias realmente no se han explicado.
Respuestas:
Al investigar el comentario de Matt, he revisado mi declaración original. Tiene razón, habrá una diferencia en el rendimiento entre una función con valor de tabla en línea (ITVF) y una función con valor de tabla de varias instrucciones (MSTVF) incluso si ambas simplemente ejecutan una instrucción SELECT. SQL Server tratará una ITVF como algo así
VIEW
ya que calculará un plan de ejecución utilizando las últimas estadísticas en las tablas en cuestión. Un MSTVF es equivalente a rellenar todo el contenido de su instrucción SELECT en una variable de tabla y luego unirse a eso. Por lo tanto, el compilador no puede usar ninguna estadística de tabla en las tablas en el MSTVF. Entonces, en igualdad de condiciones (lo cual rara vez lo son), el ITVF funcionará mejor que el MSTVF. En mis pruebas, la diferencia de rendimiento en el tiempo de finalización fue insignificante, sin embargo, desde el punto de vista estadístico, fue notable.En su caso, las dos funciones no son funcionalmente equivalentes. La función MSTV realiza una consulta adicional cada vez que se llama y, lo más importante, filtra la identificación del cliente. En una consulta grande, el optimizador no podría aprovechar otros tipos de combinaciones, ya que necesitaría llamar a la función para cada ID de cliente aprobada. Sin embargo, si reescribió su función MSTV así:
En una consulta, el optimizador podría llamar a esa función una vez y construir un mejor plan de ejecución, pero aún así no sería mejor que un ITVS o un a equivalente no parametrizado
VIEW
.Las ITVF deben preferirse a las MSTVF cuando sea factible debido a los tipos de datos, la nulabilidad y la clasificación de las columnas de la tabla, mientras que declara esas propiedades en una función con valores de tabla de múltiples declaraciones y, lo que es más importante, obtendrá mejores planes de ejecución de la ITVF. En mi experiencia, no he encontrado muchas circunstancias en las que un ITVF fuera una mejor opción que un VIEW, pero el kilometraje puede variar.
Gracias a Matt
Adición
Desde que vi esto surgir recientemente, aquí hay un excelente análisis realizado por Wayne Sheffield que compara la diferencia de rendimiento entre las funciones Inline Table Valued y las funciones Multi-Statement.
Su publicación original del blog.
Copiar en SQL Server Central
fuente
Internamente, SQL Server trata una función con valor de tabla en línea de forma muy similar a como lo haría con una vista y trata una función con valor de tabla de varias instrucciones de forma similar a como sería un procedimiento almacenado.
Cuando se utiliza una función en línea con valores de tabla como parte de una consulta externa, el procesador de consultas expande la definición UDF y genera un plan de ejecución que accede a los objetos subyacentes, utilizando los índices de estos objetos.
Para una función con valores de tabla de varias instrucciones, se crea un plan de ejecución para la función misma y se almacena en la caché del plan de ejecución (una vez que la función se ha ejecutado por primera vez). Si se utilizan funciones con valores de tabla de varias instrucciones como parte de consultas más grandes, entonces el optimizador no sabe qué devuelve la función y, por lo tanto, hace algunas suposiciones estándar; en efecto, supone que la función devolverá una sola fila y que los retornos de Se accederá a la función utilizando un escaneo de tabla contra una tabla con una sola fila.
Cuando las funciones con valores de tabla de varias instrucciones pueden funcionar mal es cuando devuelven un gran número de filas y se unen en consultas externas. Los problemas de rendimiento se deben principalmente al hecho de que el optimizador producirá un plan suponiendo que se devuelva una sola fila, que no será necesariamente el plan más apropiado.
Como regla general, hemos descubierto que, cuando sea posible, las funciones con valores de la tabla en línea deben usarse con preferencia a las de múltiples instrucciones (cuando el UDF se usará como parte de una consulta externa) debido a estos posibles problemas de rendimiento.
fuente
Hay otra diferencia Se puede insertar, actualizar y eliminar una función en línea con valores de tabla, como una vista. Se aplican restricciones similares: no se pueden actualizar funciones utilizando agregados, no se pueden actualizar columnas calculadas, etc.
fuente
Sus ejemplos, creo, responden muy bien la pregunta. La primera función se puede hacer como una sola selección, y es una buena razón para usar el estilo en línea. El segundo probablemente podría hacerse como una sola declaración (usando una subconsulta para obtener la fecha máxima), pero algunos codificadores pueden encontrar que es más fácil de leer o más natural hacerlo en varias declaraciones como lo ha hecho. Algunas funciones simplemente no se pueden realizar en una sola declaración, por lo que requieren la versión de varias declaraciones.
Sugiero usar el más simple (en línea) siempre que sea posible, y usar declaraciones múltiples cuando sea necesario (obviamente) o cuando la preferencia / legibilidad personal lo haga cambiar el tipeo adicional.
fuente
mire Comparando funciones en línea y con valores de tabla de múltiples declaraciones puede encontrar buenas descripciones y puntos de referencia de rendimiento
fuente
No he probado esto, pero una función de declaración múltiple almacena en caché el conjunto de resultados. Puede haber casos en los que el optimizador está pasando demasiado para alinear la función. Por ejemplo, suponga que tiene una función que devuelve un resultado de diferentes bases de datos dependiendo de lo que pase como un "Número de compañía". Normalmente, podría crear una vista con una unión y luego filtrar por número de compañía, pero descubrí que a veces el servidor sql retira toda la unión y no es lo suficientemente inteligente como para llamar a one select. Una función de tabla puede tener lógica para elegir la fuente.
fuente
Otro caso para usar una función multilínea sería evitar que el servidor SQL empuje hacia abajo la cláusula where.
Por ejemplo, tengo una tabla con los nombres de una tabla y algunos nombres de tabla están formateados como C05_2019 y C12_2018 y todas las tablas formateadas de esa manera tienen el mismo esquema. Quería fusionar todos esos datos en una tabla y analizar 05 y 12 en una columna CompNo y 2018,2019 en una columna de año. Sin embargo, hay otras tablas como ACA_StupidTable que no puedo extraer CompNo y CompYr y obtendría un error de conversión si lo intentara. Entonces, mi consulta fue en dos partes, una consulta interna que devolvió solo tablas formateadas como 'C_______', luego la consulta externa realizó una conversión de subcadena e int. es decir, Cast (Subcadena (2, 2) como int) como CompNo. Todo se ve bien, excepto que el servidor sql decidió poner mi función Cast antes de que se filtraran los resultados, por lo que obtengo un error de conversión de codificación mental. Una función de tabla de múltiples instrucciones puede evitar que eso suceda,
fuente
Quizás de una manera muy condensada. ITVF (TVF en línea): más si eres una persona DB, es una especie de vista parametrizada, toma una sola st SELECT
MTVF (TVF de múltiples declaraciones): Desarrollador, crea y carga una variable de tabla.
fuente
si va a hacer una consulta, puede unirse a su función Valor de tabla en línea como:
incurrirá en una pequeña sobrecarga y funcionará bien.
Si intenta utilizar su tabla de declaración múltiple valorada en una consulta similar, tendrá problemas de rendimiento:
porque ejecutará la función 1 vez por cada fila devuelta, ya que el conjunto de resultados aumenta, se ejecutará más y más lento.
fuente