Question

J'essaie d'optimiser une requête qui utilise une vue dans MySQL 5.1. Il semble que même si je sélectionne 1 colonne dans la vue, une analyse complète du tableau est effectuée. Est-ce le comportement attendu?

La vue est simplement un élément SELECT "Toutes les colonnes de ces tables - NON *". pour les tables que j'ai spécifiées dans la première requête ci-dessous.

C’est ce que j’explique à partir de la sélection de la colonne indexée PromotionID de la requête qui constitue la vue. Comme vous pouvez le constater, le résultat est très différent de celui affiché dans la vue.

EXPLAIN SELECT pb.PromotionID FROM PromotionBase pb INNER JOIN PromotionCart pct ON pb.PromotionID = pct.PromotionID INNER JOIN PromotionCode pc ON pb.PromotionID = pc.PromotionID WHERE pc.PromotionCode = '5TAFF312C0NT'\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pc
         type: const
possible_keys: PRIMARY,fk_pc_pb
          key: PRIMARY
      key_len: 302
          ref: const
         rows: 1
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: pb
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: pct
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: Using index
3 rows in set (0.00 sec)

La sortie lorsque je sélectionne la même chose mais dans la vue

EXPLAIN SELECT vpc.PromotionID FROM vw_PromotionCode vpc  WHERE vpc.PromotionCode = '5TAFF312C0NT'\G;
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5830
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: DERIVED
        table: pcart
         type: index
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 33
        Extra: Using index
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: pb
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: readyinteractive.pcart.PromotionID
         rows: 1
        Extra:
*************************** 4. row ***************************
           id: 2
  select_type: DERIVED
        table: pc
         type: ref
possible_keys: fk_pc_pb
          key: fk_pc_pb
      key_len: 4
          ref: readyinteractive.pb.PromotionID
         rows: 249
        Extra: Using where
*************************** 5. row ***************************
           id: 3
  select_type: UNION
        table: pp
         type: index
possible_keys: PRIMARY
          key: pp_p
      key_len: 4
          ref: NULL
         rows: 1
        Extra: Using index
*************************** 6. row ***************************
           id: 3
  select_type: UNION
        table: pb
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: readyinteractive.pp.PromotionID
         rows: 1
        Extra:
*************************** 7. row ***************************
           id: 3
  select_type: UNION
        table: pc
         type: ref
possible_keys: fk_pc_pb
          key: fk_pc_pb
      key_len: 4
          ref: readyinteractive.pb.PromotionID
         rows: 249
        Extra: Using where
*************************** 8. row ***************************
           id: 4
  select_type: UNION
        table: pcp
         type: index
possible_keys: PRIMARY
          key: pcp_cp
      key_len: 4
          ref: NULL
         rows: 1
        Extra: Using index
*************************** 9. row ***************************
           id: 4
  select_type: UNION
        table: pb
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: readyinteractive.pcp.PromotionID
         rows: 1
        Extra:
*************************** 10. row ***************************
           id: 4
  select_type: UNION
        table: pc
         type: ref
possible_keys: fk_pc_pb
          key: fk_pc_pb
      key_len: 4
          ref: readyinteractive.pb.PromotionID
         rows: 249
        Extra: Using where
*************************** 11. row ***************************
           id: 5
  select_type: UNION
        table: ppc
         type: index
possible_keys: PRIMARY
          key: ppc_pc
      key_len: 4
          ref: NULL
         rows: 1
        Extra: Using index
*************************** 12. row ***************************
           id: 5
  select_type: UNION
        table: pb
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: readyinteractive.ppc.PromotionID
         rows: 1
        Extra:
*************************** 13. row ***************************
           id: 5
  select_type: UNION
        table: pc
         type: ref
possible_keys: fk_pc_pb
          key: fk_pc_pb
      key_len: 4
          ref: readyinteractive.pb.PromotionID
         rows: 249
        Extra: Using where
*************************** 14. row ***************************
           id: 6
  select_type: UNION
        table: ppt
         type: index
possible_keys: PRIMARY
          key: ppt_pt
      key_len: 4
          ref: NULL
         rows: 1
        Extra: Using index
*************************** 15. row ***************************
           id: 6
  select_type: UNION
        table: pb
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: readyinteractive.ppt.PromotionID
         rows: 1
        Extra:
*************************** 16. row ***************************
           id: 6
  select_type: UNION
        table: pc
         type: ref
possible_keys: fk_pc_pb
          key: fk_pc_pb
      key_len: 4
          ref: readyinteractive.pb.PromotionID
         rows: 249
        Extra: Using where
*************************** 17. row ***************************
           id: NULL
  select_type: UNION RESULT
        table: <union2,3,4,5,6>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra:
17 rows in set (0.18 sec)
Était-ce utile?

La solution

Les vues dans MySQL n'étant pas indexées, elles nécessitent par conséquent une analyse complète à chaque accès. En règle générale, cela n’est utile pour Views que dans les cas où vous avez une requête statique assez complexe qui renvoie un petit jeu de résultats et que vous prévoyez d’obtenir le jeu complet à chaque fois.

Éditer: Bien sûr, View utilisera les index des tables sous-jacentes pour optimiser la vue (sinon ils n'auraient aucun sens d'utilisation), mais comme il n'y a pas d'index. Sur une vue, il n'est pas possible d'optimiser une requête WHERE sur la vue.

La construction d’index pour les vues serait coûteuse de toute façon car, bien que je n’ai essayé de profiler aucune vue, je suis à peu près certain qu’une table temporaire est construite en arrière-plan puis que le jeu de résultats est renvoyé. Il faut déjà beaucoup de temps pour construire la table temporaire, je ne voudrais pas d'une vue qui tente également de deviner quels index sont nécessaires. Le deuxième point est le fait que MySQL ne propose pas actuellement de méthode pour spécifier les index à utiliser pour une vue. Comment sait-il quels champs doivent être indexés? Devine-t-il en fonction de votre requête?

Vous pouvez envisager d'utiliser une table temporaire , car vous pouvez ensuite spécifier des index sur les champs de la table temporaire. Cependant, d’expérience, cela a tendance à être très lent.

Si tout ce que cette vue contient est un SELECT ALL FROM table1, table2, table3; alors je devrais demander pourquoi cette requête doit être dans une vue du tout? Si, pour une raison quelconque, cela est absolument nécessaire, vous pouvez utiliser une procédure stockée pour encapsuler la requête. Vous pourrez ainsi optimiser les performances tout en conservant l'avantage d'un appel plus simple à la base de données pour le jeu de résultats.

Autres conseils

J'ai approfondi la question et j'ai manqué un point d'information clé :( Ma requête de vue a en fait une union avec une autre table. Cela oblige la vue à utiliser l'algorithme TEMPORARY TABLE au lieu de l'algorithme MERGE.

L’algorithme TEMPORARY TABLE ne permet pas l’utilisation d’index dans les tables sous-jacentes.

Cela semble être un bogue dans MySQL et cela a été rapporté en 2006, mais cela ne semble pas avoir été résolu en 2009! http://forums.mysql.com/read.php?100,56681, 56681

On dirait que je vais devoir réécrire la requête en tant que jointure externe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top