Lo siguiente es un extracto de un libro sobre db design (Beginning Database Design ISBN: 0-7645-7490-6):
El peligro de usar vistas es filtrar una consulta contra una vista, esperando leer una porción muy pequeña de una tabla muy grande. Cualquier filtrado debe realizarse dentro de la vista porque cualquier filtrado contra la vista en sí se aplica después de que la consulta en la vista haya completado la ejecución. Las vistas suelen ser útiles para acelerar el proceso de desarrollo, pero a la larga pueden matar por completo el rendimiento de la base de datos.
Lo siguiente es un extracto de la documentación de PostgreSQL 9.5:
Hacer un uso liberal de las vistas es un aspecto clave del buen diseño de la base de datos SQL. Las vistas le permiten encapsular los detalles de la estructura de sus tablas, que pueden cambiar a medida que su aplicación evoluciona, detrás de interfaces consistentes.
Las dos fuentes parecen contradecirse ("no diseñar con vistas" versus "hacer diseño con vistas").
Sin embargo, en PG las vistas se implementan utilizando el sistema de reglas. Por lo tanto, posiblemente (y esta es mi pregunta) cualquier filtrado contra la vista se reescribe como un filtro dentro de la vista, lo que resulta en una ejecución de consulta única en las tablas subyacentes.
¿Es correcta mi interpretación y PG combina las cláusulas WHERE dentro y fuera de la vista? ¿O los ejecuta por separado, uno tras otro? ¿Algún ejemplo breve, autocontenido, correcto (compilable)?
SELECT * FROM my_view WHERE my_column = 'blablabla';
Mientras que el segundo se trata de usar vistas para hacer que su modelo de datos sea transparente para la aplicación que lo utiliza. Las primeras fuentes le indican que incluya el filtroWHERE my_column = 'blablabla'
dentro de la definición de la vista, ya que esto da como resultado un mejor plan de ejecución.Respuestas:
El libro esta equivocado.
Seleccionar desde una vista es exactamente tan rápido o lento como ejecutar la instrucción SQL subyacente; puede verificarlo fácilmente usando
explain analyze
.El optimizador de Postgres (y el optimizador para muchos otros DBMS modernos) podrá insertar predicados en la vista en la declaración de vista real, siempre que se trate de una declaración simple (de nuevo, esto se puede verificar usando
explain analyze
).La "mala reputación" con respecto al rendimiento se deriva, creo, de cuando usas en exceso las vistas y comienzas a construir vistas que usan vistas que usan vistas. Muy a menudo, eso da como resultado declaraciones que hacen demasiado en comparación con una declaración hecha a mano sin las vistas, por ejemplo, porque algunas tablas intermedias no serían necesarias. En casi todos los casos, el optimizador no es lo suficientemente inteligente como para eliminar esas tablas / combinaciones innecesarias o para empujar hacia abajo los predicados en múltiples niveles de vistas (esto también es cierto para otros DBMS).
fuente
explain analyze
declaración?Para darle un ejemplo de lo que explicó @a_horse :
Postgres implementa el esquema de información, que consiste en vistas (a veces complejas) que proporcionan información sobre objetos DB en forma estandarizada. Esto es conveniente y confiable, y puede ser sustancialmente más costoso que acceder directamente a las tablas del catálogo de Postgres.
Ejemplo muy simple, para obtener todas las columnas visibles de una tabla
... del esquema de información:
... del catálogo del sistema:
Compare los planes de consulta y el tiempo de ejecución de ambos con
EXPLAIN ANALYZE
.La primera consulta se basa en la vista
information_schema.columns
, que se une a varias tablas que no necesitamos para esto.La segunda consulta solo escanea la única tabla
pg_catalog.pg_attribute
, por lo tanto, mucho más rápido. (Pero la primera consulta solo necesita unos pocos ms en las bases de datos comunes).Detalles:
fuente
EDITAR:
Con disculpas, necesito retractarme de mi afirmación de que la respuesta aceptada no siempre es correcta: establece que la vista siempre es idéntica a la misma cosa escrita como una subconsulta. Creo que eso es indiscutible, y creo que ahora sé lo que está pasando en mi caso.
Ahora también creo que hay una mejor respuesta a la pregunta original.
La pregunta original es si debería ser una práctica orientadora el uso de vistas (en lugar de, por ejemplo, repetir SQL en rutinas que pueden necesitar mantenerse dos veces o más).
Mi respuesta sería "no si su consulta usa funciones de ventana o cualquier otra cosa que haga que el optimizador trate la consulta de manera diferente cuando se convierte en una subconsulta, porque el acto mismo de crear la subconsulta (ya sea representada como una vista o no) puede degradar el rendimiento si está filtrando con parámetros en tiempo de ejecución.
La complejidad de mi función de ventana es innecesaria. El plan de explicación para esto:
es mucho menos costoso que para esto:
Espero que sea un poco más específico y útil.
En mi experiencia reciente (haciéndome encontrar esta pregunta), la respuesta aceptada arriba no es correcta en todas las circunstancias. Tengo una consulta relativamente simple que incluye una función de ventana:
Si agrego este filtro:
El plan de explicación que obtengo es el siguiente:
Esto está utilizando el índice de clave primaria en la tabla de servicio del tren y un índice no único en la tabla porción_consistir. Se ejecuta en 90ms.
Creé una vista (pegándola aquí para que sea absolutamente clara, pero es literalmente la consulta en una vista):
Cuando consulto esta vista con el filtro idéntico:
Este es el plan de explicación:
Esto está haciendo escaneos completos en ambas tablas y toma 17 segundos.
Hasta que me encontré con esto, he estado usando generosamente vistas con PostgreSQL (habiendo entendido las opiniones ampliamente expresadas en la respuesta aceptada). Evitaría específicamente el uso de vistas si necesito un filtrado agregado previo, para lo cual usaría funciones de devolución de conjuntos.
También soy consciente de que los CTE en PostgreSQL se evalúan estrictamente por separado, por diseño, por lo que no los uso de la misma manera que lo haría con SQL Server, por ejemplo, donde parecen estar optimizados como subconsultas.
Mi respuesta, por lo tanto, es que hay casos en los que las vistas no funcionan exactamente como la consulta en la que se basan, por lo que se recomienda precaución. Estoy usando Amazon Aurora basado en PostgreSQL 9.6.6.
fuente
CASE WHEN (NOT ts.primary_direction) THEN '-1' :: INTEGER ELSE 1 END
será necesario que la consulta sea más lenta de lo necesario, ya que es mejor escribir dos condicionales más en el orden.CASE WHEN (NOT ts.primary_direction) THEN dense_rank() OVER (PARTITION BY ts.train_service_key ORDER BY pc.through_idx DESC, pc.first_portion ASC, pc.first_seq DESC) ELSE dense_rank() OVER (PARTITION BY ts.train_service_key ORDER BY pc.through_idx DESC, pc.first_portion ASC, pc.first_seq ASC) END AS coach_block_idx
dense_rank()
lo que no es realmente un problema de rendimiento.(Soy un gran admirador de las vistas, pero debe tener mucho cuidado con PG aquí y me gustaría animar a todos a usar vistas en general también en PG para una mejor comprensión y facilidad de mantenimiento de consultas / código)
En realidad y tristemente (ADVERTENCIA :) el uso de vistas en Postgres nos causó problemas reales y disminuyó gravemente nuestro rendimiento dependiendo de las características que estábamos usando dentro de él :-( (al menos con v10.1). (Esto no sería así con otros sistemas de bases de datos modernos como Oracle).
(Dependiendo de lo que quiera decir exactamente, no, las tablas temporales intermedias pueden materializarse como tal vez no desee o donde no se presionen los predicados ...)
Conozco al menos dos "características" principales, que nos decepcionaron en medio de las migraciones de Oracle a Postgres, por lo que tuvimos que abandonar PG en un proyecto:
Los CTE (
with
subconsultas de cláusula / expresiones de tabla comunes ) son (generalmente) útiles para estructurar consultas más complejas (incluso en aplicaciones más pequeñas), pero en PG se implementan por diseño como sugerencias optimizadoras "ocultas" (que generan, por ejemplo, tablas temporales no indexadas) y violar así el concepto (para mí y para muchos otros importantes) de SQL declarativo ( documento de Oracle ): por ejemploconsulta simple:
reescrito usando algo de CTE:
Más fuentes con discusiones, etc .: https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/
Las funciones de ventana con
over
-declaraciones son potencialmente inutilizables (normalmente se utilizan en vistas, por ejemplo, como fuente de informes basados en consultas más complejas)nuestra solución para las
with
cláusulasTransformaremos todas las "vistas en línea" en vistas reales con un prefijo especial para que no alteren la lista / espacio de nombres de las vistas y puedan relacionarse fácilmente con la "vista externa" original: - /
nuestra solución para las funciones de ventana
Lo implementamos con éxito utilizando la base de datos Oracle.
fuente