Mysql
 sql >> Base de données >  >> RDS >> Mysql

Performances MySQL de VIEW pour les tables combinées avec UNION ALL

Je suis d'accord avec tous les points de l'excellente réponse de Bill Karwin.

Q : Est-il normal de créer une vue pour la requête d'union discutée et de l'utiliser dans mes jointures, sous-sélections, etc. ?

R : Avec MySQL, la pratique la plus normale consiste à éviter d'utiliser l'instruction "CREATE VIEW".

Q : En termes de performances - sera-t-il pire, égal ou meilleur par rapport au simple fait de l'insérer dans des jointures, des sous-sélections, etc.?

R : Le référencement d'un objet de vue aura les mêmes performances qu'une vue en ligne équivalente.

(Il peut y avoir un tout petit peu plus de travail pour rechercher l'objet de vue, vérifier les privilèges, puis remplacer la référence de vue par le SQL stocké, par rapport à l'envoi d'une instruction qui est juste un tout petit peu plus longue. les différences sont insignifiantes.)

Q : Y a-t-il des inconvénients à avoir une vue dans ce cas ?

R : Le plus gros inconvénient réside dans la façon dont MySQL traite une vue, qu'elle soit stockée ou en ligne. MySQL exécutera toujours la requête de vue et matérialisera les résultats de cette requête sous la forme d'une table MyISAM temporaire. Mais il n'y a aucune différence si la définition de la vue est stockée ou si elle est incluse en ligne. (Les autres SGBDR traitent les vues très différemment de MySQL).

Un gros inconvénient d'une vue est que les prédicats de la requête externe ne sont JAMAIS poussés vers le bas dans la requête de vue. Chaque fois que vous faites référence à cette vue, même avec une requête pour une seule valeur d'identifiant, MySQL va exécuter la requête de vue et créer une table MyISAM temporaire (sans index dessus), et ALORS MySQL exécutera la requête externe sur cette valeur temporaire. Table MyISAM.

Donc, en termes de performances, pensez à une référence à une vue comparable à "CREATE TEMPORARY TABLE t (cols) ENGINE=MyISAM " et "INSERT INTO t (cols) SELECT ... ".

MySQL fait en fait référence à une vue en ligne comme une "table dérivée", et ce nom a beaucoup de sens, quand on comprend ce que MySQL en fait.

Ma préférence personnelle est de ne pas utiliser l'instruction "CREATE VIEW". Le plus gros inconvénient (selon moi) est qu'il "cache" le SQL en cours d'exécution. Pour le futur lecteur, la référence à la vue ressemble à un tableau. Et puis, quand il va écrire une instruction SQL, il va référencer la vue comme si c'était une table, donc très pratique. Puis il décide qu'il va joindre cette table à elle-même, avec une autre référence à celle-ci. (Pour la deuxième référence, MySQL exécute également à nouveau cette requête et crée une autre table MyISAM temporaire (et non indexée). Et maintenant, il y a une opération JOIN à ce sujet. Et puis un prédicat "WHERE view.column ='foo'" est ajouté sur la requête externe.

Cela finit par "masquer" l'amélioration des performances la plus évidente, en glissant ce prédicat dans la requête de vue.

Et puis, quelqu'un arrive et décide qu'il va créer une nouvelle vue, qui fait référence à l'ancienne vue. Il n'a besoin que d'un sous-ensemble de lignes et ne peut pas modifier la vue existante car cela pourrait casser quelque chose. Il crée donc une nouvelle vue... CREATE VIEW myview FROM publicview p WHERE p.col ='foo'.

Et, maintenant, une référence à myview va d'abord exécuter la requête publicview, créer une table temporaire MyISAM, puis la requête myview est exécutée sur celle-ci, créant une autre table temporaire MyISAM, sur laquelle la requête externe va s'exécuter.

Fondamentalement, la commodité de la vue peut entraîner des problèmes de performances involontaires. Avec la définition de vue disponible sur la base de données pour que n'importe qui puisse l'utiliser, quelqu'un va l'utiliser, même si ce n'est pas la solution la plus appropriée.

Au moins avec une vue en ligne, la personne qui écrit l'instruction SQL est plus consciente du SQL réel en cours d'exécution, et le fait d'avoir tout ce SQL présenté donne la possibilité de l'ajuster pour les performances.

Mes deux sous.

APPRIVOISER BEASTLY SQL

Je trouve que l'application de règles de formatage régulières (que mes outils font automatiquement) peut transformer un code SQL monstrueux en quelque chose que je peux lire et utiliser.

SELECT row.col1
     , row.col2
     , person.*
  FROM some_table row
  LEFT
  JOIN ( SELECT 'person'  AS `person_type`
              , p.id      AS `id`
              , CONCAT(p.first_name,' ',p.surname) AS `name`
           FROM person p
          UNION ALL
         SELECT 'company' AS `person_type`
              , c.id      AS `id`
              , c.name    AS `name`
           FROM company c
       ) person
    ON person.id = row.person_id
   AND person.person_type = row.person_type

Je serais tout aussi susceptible d'éviter la vue en ligne et d'utiliser des expressions conditionnelles dans la liste SELECT, bien que cela devienne plus compliqué pour de nombreuses colonnes.

SELECT row.col1
     , row.col2
     , row.person_type AS ref_person_type
     , row.person_id   AS ref_person_id
     , CASE
       WHEN row.person_type = 'person'  THEN p.id 
       WHEN row.person_type = 'company' THEN c.id
       END AS `person_id`
     , CASE
       WHEN row.person_type = 'person'  THEN CONCAT(p.first_name,' ',p.surname)
       WHEN row.person_type = 'company' THEN c.name
       END AS `name`
  FROM some_table row
  LEFT
  JOIN person p
    ON row.person_type = 'person'
   AND p.id = row.person_id
  LEFT
  JOIN company c
    ON row.person_type = 'company'
   AND c.id = row.person_id