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:
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
count(*) OVER
(PARTITION BY ts.train_service_key) AS train_records
FROM staging.train_service ts
JOIN staging.portion_consist pc
USING (ds_code, train_service_key)
WHERE assembly_key = '185132';
es mucho menos costoso que para esto:
SELECT *
FROM (SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
count(*) OVER
(PARTITION BY ts.train_service_key) AS train_records
FROM staging.train_service ts
JOIN staging.portion_consist pc
USING (ds_code, train_service_key)) AS query
WHERE assembly_key = '185132';
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:
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
dense_rank() OVER (PARTITION BY ts.train_service_key
ORDER BY pc.through_idx DESC, pc.first_portion ASC,
((CASE WHEN (NOT ts.primary_direction)
THEN '-1' :: INTEGER
ELSE 1
END) * pc.first_seq)) AS coach_block_idx
FROM (staging.train_service ts
JOIN staging.portion_consist pc USING (ds_code, train_service_key))
Si agrego este filtro:
where assembly_key = '185132'
El plan de explicación que obtengo es el siguiente:
QUERY PLAN
Unique (cost=11562.66..11568.77 rows=814 width=43)
-> Sort (cost=11562.66..11564.70 rows=814 width=43)
Sort Key: ts.train_service_key, (dense_rank() OVER (?))
-> WindowAgg (cost=11500.92..11523.31 rows=814 width=43)
-> Sort (cost=11500.92..11502.96 rows=814 width=35)
Sort Key: ts.train_service_key, pc.through_idx DESC, pc.first_portion, ((CASE WHEN (NOT ts.primary_direction) THEN '-1'::integer ELSE 1 END * pc.first_seq))
-> Nested Loop (cost=20.39..11461.57 rows=814 width=35)
-> Bitmap Heap Scan on portion_consist pc (cost=19.97..3370.39 rows=973 width=38)
Recheck Cond: (assembly_key = '185132'::text)
-> Bitmap Index Scan on portion_consist_assembly_key_index (cost=0.00..19.72 rows=973 width=0)
Index Cond: (assembly_key = '185132'::text)
-> Index Scan using train_service_pk on train_service ts (cost=0.43..8.30 rows=1 width=21)
Index Cond: ((ds_code = pc.ds_code) AND (train_service_key = pc.train_service_key))
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):
CREATE OR REPLACE VIEW staging.v_unit_coach_block AS
SELECT DISTINCT ts.train_service_key,
pc.assembly_key,
dense_rank() OVER (PARTITION BY ts.train_service_key
ORDER BY pc.through_idx DESC, pc.first_portion ASC, (
(CASE
WHEN (NOT ts.primary_direction)
THEN '-1' :: INTEGER
ELSE 1
END) * pc.first_seq)) AS coach_block_idx
FROM (staging.train_service ts
JOIN staging.portion_consist pc USING (ds_code, train_service_key))
Cuando consulto esta vista con el filtro idéntico:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
Este es el plan de explicación:
QUERY PLAN
Subquery Scan on v_unit_coach_block (cost=494217.13..508955.10 rows=3275 width=31)
Filter: (v_unit_coach_block.assembly_key = '185132'::text)
-> Unique (cost=494217.13..500767.34 rows=655021 width=43)
-> Sort (cost=494217.13..495854.68 rows=655021 width=43)
Sort Key: ts.train_service_key, pc.assembly_key, (dense_rank() OVER (?))
-> WindowAgg (cost=392772.16..410785.23 rows=655021 width=43)
-> Sort (cost=392772.16..394409.71 rows=655021 width=35)
Sort Key: ts.train_service_key, pc.through_idx DESC, pc.first_portion, ((CASE WHEN (NOT ts.primary_direction) THEN '-1'::integer ELSE 1 END * pc.first_seq))
-> Hash Join (cost=89947.40..311580.26 rows=655021 width=35)
Hash Cond: ((pc.ds_code = ts.ds_code) AND (pc.train_service_key = ts.train_service_key))
-> Seq Scan on portion_consist pc (cost=0.00..39867.86 rows=782786 width=38)
-> Hash (cost=65935.36..65935.36 rows=1151136 width=21)
-> Seq Scan on train_service ts (cost=0.00..65935.36 rows=1151136 width=21)
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.
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.