Ce qui suit est un extrait d’un livre sur la conception de la base de données (ISBN: 0-7645-7490-6):
Le danger lié à l'utilisation de vues est le filtrage d'une requête par rapport à une vue, en s'attendant à lire une très petite partie d'un très grand tableau. Tout filtrage doit être effectué dans la vue, car il est appliqué après la fin de l'exécution de la requête dans la vue. Les vues sont généralement utiles pour accélérer le processus de développement, mais peuvent à long terme détruire complètement les performances de la base de données.
Ce qui suit est un extrait de la documentation de PostgreSQL 9.5:
L'utilisation généralisée des vues est un aspect essentiel d'une bonne conception de base de données SQL. Les vues vous permettent d'encapsuler les détails de la structure de vos tables, qui peuvent changer en fonction de l'évolution de votre application, derrière des interfaces cohérentes.
Les deux sources semblent se contredire ("ne concevez pas avec des vues" ou "ne concevez avec des vues").
Cependant, dans les vues PG, elles sont implémentées à l'aide du système de règles. Donc, éventuellement (et c'est ma question), tout filtrage de la vue est réécrit en tant que filtre dans la vue, ce qui entraîne l'exécution d'une requête unique sur les tables sous-jacentes.
Mon interprétation est-elle correcte et PG combine les clauses WHERE dans et hors de la vue? Ou est-ce qu'il les exécute séparément, l'un après l'autre? Des exemples courts, autonomes, corrects (compilables)?
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.Réponses:
Le livre est faux.
La sélection dans une vue est exactement aussi rapide ou lente que l'exécution de l'instruction SQL sous-jacente - vous pouvez facilement vérifier cela à l'aide de
explain analyze
.L'optimiseur Postgres (et l'optimiseur de nombreux autres SGBD modernes) sera capable d'insérer des prédicats de la vue dans la déclaration réelle, à condition qu'il s'agisse d'une simple déclaration (à nouveau, elle peut être vérifiée à l'aide de
explain analyze
).Je pense que la "mauvaise réputation" en matière de performances découle du fait que vous abusez des vues et commencez à créer des vues qui utilisent des vues qui utilisent des vues. Très souvent, cela donne des déclarations qui en font trop par rapport à une déclaration qui a été personnalisée à la main sans les vues, par exemple parce que certaines tables intermédiaires ne seraient pas nécessaires. Dans presque tous les cas, l'optimiseur n'est pas assez intelligent pour supprimer ces tables / jointures inutiles ou pour abaisser les prédicats sur plusieurs niveaux de vues (cela s'applique également aux autres SGBD).
la source
explain analyze
déclaration?Pour vous donner un exemple de ce que @a_horse a expliqué :
Postgres implémente le schéma d'information, constitué de vues (parfois complexes) fournissant des informations sur les objets de base de données sous une forme normalisée. C'est pratique et fiable - et peut coûter beaucoup plus cher que d'accéder directement aux tables du catalogue Postgres.
Exemple très simple, pour obtenir toutes les colonnes visibles d'une table
... à partir du schéma d'information:
... depuis le catalogue système:
Comparez les plans de requête et le temps d'exécution pour les deux avec
EXPLAIN ANALYZE
.La première requête est basée sur la vue
information_schema.columns
, qui rejoint plusieurs tables dont nous n’avons pas besoin pour cela.La deuxième requête scanne seulement un tableau
pg_catalog.pg_attribute
, donc beaucoup plus rapide. (Mais la première requête n'a toujours besoin que de quelques ms dans les bases de données communes.)Détails:
la source
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:
est beaucoup moins coûteux que pour cela:
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:
Si j'ajoute ce filtre:
Le plan d’explication que j’obtiens est le suivant:
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):
Lorsque j'interroge cette vue avec le filtre identique:
C'est le plan d'expliquer:
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.
la source
CASE WHEN (NOT ts.primary_direction) THEN '-1' :: INTEGER ELSE 1 END
sera inutile de ralentir la requête plus que nécessaire, il est préférable d'écrire deux autres conditions dans la commande.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()
, ce n’est donc pas vraiment un problème de performances.(Je suis un grand fan de vues, mais vous devez être très prudent avec PG ici et je voudrais encourager tout le monde à utiliser les vues de manière générale également dans PG pour une meilleure compréhension et maintenance des requêtes / du code.)
En réalité et malheureusement (AVERTISSEMENT :), l’ utilisation de vues dans Postgres nous posait de véritables problèmes et réduisait considérablement nos performances en fonction des fonctionnalités que nous utilisions à l’intérieur :-( (au moins avec la version 10.1). systèmes de base de données modernes comme Oracle.)
(En fonction de ce que vous voulez dire exactement - non - des tables de températures intermédiaires peuvent être matérialisées que vous ne voulez pas être ou des prédicats ne sont pas enfoncés ...)
Je connais au moins deux fonctionnalités principales, qui nous ont laissés au milieu des migrations d’Oracle à Postgres , nous avons donc dû abandonner PG dans un projet:
CTEs (
with
sous - requêtes -clause / expressions de table communes ) sont (généralement) utiles pour structurer des requêtes plus complexes (même dans des applications plus petites), mais dans PG sont par la conception mises en œuvre comme « cachées » optimiseur conseils (générant par exemple des tables temporaires non indexées) et viole donc le concept (pour moi et beaucoup d’autres importants) de SQL déclaratif ( docu Oracle ): par exemplerequête simple:
réécrit en utilisant un CTE:
Autres sources avec discussions, etc.: https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/
les fonctions de fenêtre avec
over
-tatements sont potentiellement inutilisables (généralement utilisées dans les vues, par exemple comme source pour les rapports basés sur des requêtes plus complexes)notre solution de contournement pour les
with
clausesNous allons transformer toutes les "vues en ligne" en vues réelles avec un préfixe spécial afin qu'elles ne perturbent pas la liste / l'espace de noms des vues et qu'elles puissent être facilement associées à la "vue extérieure" d'origine: - /
notre solution pour les fonctions de fenêtre
Nous l'avons implémenté avec succès en utilisant la base de données Oracle.
la source