MODIFIER:
Avec des excuses, je dois retirer mon affirmation selon laquelle la réponse acceptée n'est pas toujours correcte - elle indique que la vue est toujours identique à la même chose écrite en tant que sous-requête. Je pense que c'est indiscutable et que je sais maintenant ce qui se passe dans mon cas.
Je pense aussi qu'il existe une meilleure réponse à la question initiale.
La question initiale était de savoir s'il fallait guider l'utilisation de vues (par exemple, la répétition de SQL dans des routines pouvant nécessiter une maintenance deux fois ou plus).
Ma réponse serait "pas si votre requête utilise des fonctions de fenêtre ou quoi que ce soit qui amène l'optimiseur à traiter la requête différemment lorsqu'elle devient une sous-requête, car le simple fait de créer la sous-requête (représentée ou non sous forme de vue) risque de dégrader les performances. si vous filtrez avec des paramètres au moment de l'exécution.
La complexité de ma fonction de fenêtre est inutile. Le plan d'explication pour ceci:
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';
est beaucoup moins coûteux que pour cela:
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';
J'espère que c'est un peu plus précis et utile.
Dans mon expérience récente (qui m'a amené à trouver cette question), la réponse acceptée ci-dessus n'est pas correcte dans toutes les circonscriptions. J'ai une requête relativement simple qui inclut une fonction de fenêtre:
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 j'ajoute ce filtre:
where assembly_key = '185132'
Le plan d’explication que j’obtiens est le suivant:
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))
Cela utilise l'index de clé primaire sur la table de service de train et un index non unique sur la table portion_consist. Il s'exécute en 90ms.
J'ai créé une vue (la coller ici pour être absolument claire, mais c'est littéralement la requête dans une vue):
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))
Lorsque j'interroge cette vue avec le filtre identique:
select * from staging.v_unit_coach_block
where assembly_key = '185132';
C'est le plan d'expliquer:
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)
Cela effectue des analyses complètes sur les deux tables et prend 17 secondes.
Jusqu'à ce que je trouve cela, j'utilisais généreusement des vues avec PostgreSQL (ayant compris les vues largement partagées exprimées dans la réponse acceptée). J'éviterais spécifiquement d'utiliser des vues si j'avais besoin d'un filtrage pré-agrégé, pour lequel j'utiliserais des fonctions de renvoi de jeu.
Je suis également conscient du fait que les CTE de PostgreSQL sont évalués séparément, de par leur conception. Je ne les utilise donc pas comme je le ferais avec SQL Server, par exemple, où ils semblent être optimisés en tant que sous-requêtes.
Ma réponse est donc la suivante: dans certains cas, les vues ne fonctionnent pas exactement comme la requête sur laquelle elles sont basées. Il est donc conseillé de faire preuve de prudence. J'utilise Amazon Aurora basé sur PostgreSQL 9.6.6.
SELECT * FROM my_view WHERE my_column = 'blablabla';
.La seconde concerne l'utilisation des vues pour rendre votre modèle de données transparent pour l'application qui l'utilise. Les premières sources vous invitent à inclure le filtreWHERE my_column = 'blablabla'
dans la définition de la vue, afin d’améliorer le plan d’exécution.