sql >> Base de Datos >  >> RDS >> Database

Los 3 mejores consejos que necesita saber para escribir vistas SQL más rápidas

¿Amigo o enemigo? Las vistas de SQL Server han sido objeto de acalorados debates cuando estaba en mi primer año usando SQL Server. Decían que era malo porque era lento. Pero, ¿qué tal hoy?

¿Estás en el mismo barco que yo hace muchos años? Entonces, únase a mí en este viaje para desentrañar el verdadero negocio de las vistas SQL para que pueda escribirlas lo más rápido posible.

Las vistas SQL son tablas virtuales. Los registros en una vista son el resultado de una consulta dentro de ella. Cada vez que se actualizan las tablas base utilizadas en la vista, también se actualiza la vista. También puede INSERTAR, ACTUALIZAR y ELIMINAR registros en una vista como una tabla en algunos casos. Aunque no lo he probado yo mismo.

De manera similar a una tabla, puede CREAR, ALTERAR o ELIMINAR una vista. Incluso puede crear un índice, con algunas restricciones.

Tenga en cuenta que utilicé SQL Server 2019 en los códigos de muestra.

1. Conozca el uso correcto e incorrecto de las vistas SQL

Primero, lo básico.

¿Para qué sirven las vistas SQL?

Es crucial. Si lo usa como un martillo para un destornillador, olvídese de las vistas SQL más rápidas. Primero, recordemos el uso adecuado:

  • Para enfocar, simplificar y personalizar la percepción que cada usuario tiene de la base de datos.
  • Para permitir que los usuarios accedan a la única información que necesitan ver por razones de seguridad.
  • Para proporcionar compatibilidad con versiones anteriores a una tabla antigua o un esquema antiguo para no dañar las aplicaciones dependientes. Es temporal hasta que se completen todos los cambios necesarios.
  • Para particionar datos provenientes de diferentes servidores. Por lo tanto, aparecen como si fueran una tabla de un servidor o instancia.

¿Cómo NO usar las vistas de SQL Server?

  • Reutilice la vista en otra vista que se reutilizará en otra vista. En resumen, vistas profundamente anidadas. La reutilización del código tiene algunos inconvenientes en este caso.
  • Ahorre en pulsaciones de teclas. Se relaciona con el primero, que reduce la presión de los dedos y parece acelerar la codificación.

El uso inadecuado de las vistas, si está permitido, oscurecerá la verdadera razón por la que crea las vistas. Como verá más adelante, los beneficios reales superan los beneficios percibidos del uso inadecuado.

Ejemplo

Inspeccionemos un ejemplo de Microsoft. El vEmpleado vista desde AdventureWorks . Aquí está el código:

-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee] 
AS 
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
 ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO

El propósito de esta vista se centra en la información básica del empleado. Si lo necesita un personal de recursos humanos, se puede mostrar en una página web. ¿Se reutilizó en otras vistas?

Prueba esto:

  1. En SQL Server Management Studio , busca AdventureWorks base de datos.
  2. Expanda la carpeta Vistas y busque [HumanResources].[vEmployee].
  3. Haz clic derecho y selecciona Ver dependencias .

Si ve otra vista que depende de esta vista, que luego depende de una vista diferente, Microsoft nos dio un mal ejemplo. Pero entonces, no hay otras dependencias de vista.

Pasemos al siguiente.

2. Desacreditar el mito de las vistas SQL

Cuando SQL Server procesa un SELECT desde una vista , evalúa el código en la vista ANTES de tratar con la cláusula WHERE o cualquier unión en la consulta externa. Con más mesas unidas, será lento en comparación con SELECCIONAR desde tablas base con los mismos resultados.

Al menos, es lo que me dijeron cuando comencé a usar SQL. Ya sea un mito o no, solo hay una forma de averiguarlo. Pasemos a un ejemplo práctico.

Cómo funcionan las vistas SQL

Microsoft no nos dejó en la oscuridad para debatir interminablemente. Tenemos las herramientas para ver cómo funcionan las consultas, como STATISTICS IO y el Plan de ejecución real . Los usaremos en todos nuestros ejemplos. Vamos a tener el primero.

USE AdventureWorks
GO

SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

Para ver qué sucede cuando SQL Server procesa la vista, inspeccionemos el Plan de ejecución real en la Figura 1. Lo comparamos con el código CREATE VIEW para vEmployee en la sección anterior.

Como puede ver, los primeros nodos procesados ​​por SQL Server son los que usan INNER JOIN. Luego, procede a procesar las UNIONES EXTERNAS IZQUIERDAS.

Dado que no podemos ver un nodo Filter en ninguna parte para la cláusula WHERE, debe estar en uno de esos nodos. Si inspecciona las propiedades de todos los nodos, verá la cláusula WHERE procesada en la tabla Empleado. Lo encerré en un cuadro en la Figura 1. Para probar que está ahí, vea la Figura 2 para ver las Propiedades de ese nodo:

Análisis

Entonces, tenía la declaración SELECT en el vEmployee vista se evaluó o procesó ANTES de que se aplicara la cláusula WHERE? El Plan de Ejecución muestra que no fue así. Si lo fuera, debería aparecer más cerca del nodo SELECT.

Lo que me dijeron fue un mito. Estaba evitando algo bueno debido a un malentendido sobre el uso adecuado de las vistas SQL.

Ahora que sabemos cómo SQL Server procesa un SELECT desde una vista , la pregunta sigue siendo:¿es más lento que no usar una vista?

SELECT FROM View vs. SELECT FROM Base Tables:¿cuál se ejecutará más rápido?

Primero, necesitamos extraer la declaración SELECT dentro del vEmployee view y produzca el mismo resultado que tuvimos al usar la vista. El siguiente código muestra la misma cláusula WHERE:

USE AdventureWorks
GO

-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

-- SELECT FROM Base Tables
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
	ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105

Luego, inspeccionamos el IO de ESTADÍSTICAS y hacemos un Comparar Showplan . ¿Cuántos recursos necesitará una consulta desde una vista en comparación con una consulta desde tablas base? Consulte la figura 3.

Aquí, consultar desde una vista o tablas base consumirá las mismas lecturas lógicas. Ambos utilizaron páginas de 19 * 8 KB. Basado en esto, es un empate sobre quién es más rápido. En otras palabras, usar una vista no perjudicará el rendimiento. Comparemos el plan de ejecución real de ambos usando el Comparar Showplan :

¿Ves la parte sombreada del diagrama? ¿Qué tal el QueryPlanHash? ¿de ambos? Dado que ambas consultas tienen el mismo QueryPlanHash y las mismas operaciones, ya sea la vista o las tablas base serán procesadas de la misma manera por SQL Server .

Las mismas lecturas lógicas y el mismo plan de la muestra nos dicen que ambos realizarán lo mismo. Por lo tanto, tener lecturas lógicas altas hará que su consulta se ejecute lentamente, ya sea que use vistas o no. Conocer este hecho lo ayudará a solucionar el problema y hará que su vista se ejecute más rápido.

Desafortunadamente, hay malas noticias.

Unir vistas SQL a tablas

Lo que vio anteriormente es una SELECCIÓN de una vista sin uniones. Sin embargo, ¿qué sucede si une una tabla a una vista?

Revisemos otro ejemplo. Esta vez, usamos el vSalesPerson ver en AdventureWorks – una lista de vendedores con información de contacto y cuota de ventas. Nuevamente, comparamos la declaración con un SELECT de las tablas base:

-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT 
 sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName

-- using base tables
SELECT
 p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName 

Si crees que también será lo mismo, consulta las ESTADÍSTICAS IO:

¿Sorprendido? Unirse al vSalesPerson ver con el SalesOrderHeader La tabla necesita recursos tremendos (28,240 x 8 KB) en comparación con solo usar las tablas base (774 x 8 KB). Observe también que incluía algunas tablas que no necesitábamos (las tablas dentro de los recuadros rojos). Por no hablar de lecturas lógicas más altas en SalesOrderHeader al usar la vista.

Pero no termina ahí.

El plan de ejecución real revela más

Observe el plan de ejecución real de la consulta a las tablas base:

La ilustración parece mostrar un Plan de Ejecución bastante normal. Pero mira el que tiene la vista:

El plan de ejecución de la Figura 7 coincide con el IO de ESTADÍSTICAS de la Figura 5. Podemos ver las tablas que no necesitamos desde la vista. También hay una búsqueda de claves nodo con una fila estimada que tiene más de mil registros fuera de las filas reales. Finalmente, también aparece una advertencia en el nodo SELECT. ¿Qué podría ser?

¿Qué es eso ExcessiveGrant? advertencia en el nodo SELECT?

Una concesión excesiva ocurre cuando la memoria máxima utilizada es demasiado pequeña en comparación con la memoria concedida. En este caso, se otorgaron 1024 KB, pero solo se usaron 16 KB.

La concesión de memoria es la cantidad estimada de memoria en KB necesaria para ejecutar el plan.

Podrían ser estimaciones incorrectas en la Búsqueda de claves node y/o la inclusión de las tablas que no necesitábamos en el plan que causó esto. Además, demasiada memoria otorgada puede causar bloqueo. Los 1008 KB restantes podrían haber sido útiles para otras operaciones.

Eventualmente, algo salió mal cuando unió la vista con una tabla. No tenemos que lidiar con estos problemas si consultamos desde las tablas base.

Puntos para llevar

Fue una larga explicación. Sin embargo, sabemos que las vistas no se evalúan ni procesan ANTES de que se evalúen una cláusula WHERE o uniones en la consulta externa. También demostramos que ambos funcionarían de la misma manera.

Por otro lado, hay un caso cuando unimos una vista a una tabla. Utiliza uniones de tablas que no necesitamos de la vista. Son invisibles para nosotros a menos que verifiquemos las ESTADÍSTICAS IO y el Plan de Ejecución Real. Todo puede perjudicar el rendimiento y los problemas pueden surgir de la nada.

Por lo tanto:

  • Deberíamos saber cómo funcionan las consultas, incluidas las vistas, desde adentro.
  • STATISTICS IO y Actual Execution Plans revelarán cómo funcionarán las consultas y las vistas.
  • No podemos simplemente unir una vista a una tabla y reutilizarla sin cuidado. ¡Revise siempre las ESTADÍSTICAS IO y los Planes de Ejecución Reales! En lugar de reutilizar las vistas y anidarlas para lograr una productividad de codificación "mejorada", utilizo IntelliSense y la herramienta de finalización de código como SQL Complete.

Entonces podemos estar seguros de no escribir vistas que tendrán resultados correctos sino que se ejecutarán como un caracol.

3. Pruebe las vistas indexadas

Las vistas indexadas son lo que su nombre implica. Puede dar un impulso de rendimiento a las declaraciones SELECT. Pero al igual que los índices de las tablas, puede afectar el rendimiento si las tablas base son grandes y se actualizan continuamente.

Para ver cómo las vistas indexadas pueden mejorar el rendimiento de las consultas, examinemos vStateProvinceCountryRegion ver en AdventureWorks . La vista está indexada en StateProvinceID y Código de región del país . Es un índice único agrupado.

Comparemos las ESTADÍSTICAS IO de la vista que no tiene el índice y que tiene un índice. Con esto, sabemos cuántas páginas de 8 KB leerá nuestro SQL Server:

La figura muestra que tener un índice en vStateProvinceCountryRegion view reduce las lecturas lógicas a la mitad. Es una mejora del 50% en comparación con no tener un índice.

Es bueno escuchar eso.

Aún así, nuevamente, no agregue índices a sus vistas sin cuidado. Además de tener una larga lista de reglas estrictas para tener 1 índice agrupado único, puede perjudicar el rendimiento, al igual que agregar índices a las tablas con desenvoltura. Además, verifique STATISTICS IO si hay una disminución en las lecturas lógicas después de agregar el índice.

Puntos para llevar

Como hemos visto en nuestro ejemplo, las vistas indexadas pueden mejorar el rendimiento de las vistas SQL.

Consejo ADICIONAL

Al igual que cualquier otra consulta, las vistas de SQL se ejecutarán rápidamente si:

  • Las estadísticas se actualizan
  • Se agregaron los índices faltantes
  • Los índices están desfragmentados
  • Los índices usaron el FACTOR DE RELLENO correcto

Conclusión

¿Las vistas SQL son buenas o malas?

Las vistas SQL son buenas si las escribimos correctamente y verificamos cómo se procesarán. Tenemos herramientas como STATISTICS IO y Actual Execution Plan. ¡Úselas! Las vistas indexadas también pueden mejorar el rendimiento.

¿Como esta publicación? Comparte un poco de amor en tu plataforma de redes sociales favorita.