Pregunta

Estoy tratando de optimizar una consulta que usa una vista en MySQL 5.1. Parece que incluso si selecciono 1 columna de la vista, siempre realiza un escaneo completo de la tabla. ¿Es ese el comportamiento esperado?

La vista es solo un SELECCIONAR " Todas las columnas de estas tablas - NO * " para las tablas que he especificado en la primera consulta a continuación.

Esta es mi salida de explicación de cuando selecciono la columna indexada PromotionID de la consulta que constituye la vista. Como puede ver, es muy diferente del resultado en la vista.

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 salida cuando selecciono lo mismo pero desde la vista

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)
¿Fue útil?

Solución

Las vistas en MySQL no están indexadas, por lo que, por su propia naturaleza, requieren un análisis completo cada vez que se accede a ellas. En términos generales, esto hace que las vistas realmente solo sean útiles para situaciones en las que tiene una consulta estática bastante compleja que devuelve un pequeño conjunto de resultados y planea tomar todo el conjunto de resultados cada vez.

Editar: Por supuesto, las Vistas usarán los índices en las tablas subyacentes para que la Vista en sí misma esté optimizada (de lo contrario, no tendría ningún sentido usarla) pero porque no hay índices en una vista no es posible optimizar una consulta WHERE en la vista.

Construir índices para Vistas sería costoso de todos modos porque, aunque no he intentado perfilar ninguna Vista, estoy bastante seguro de que se construye una tabla temporal detrás de escena y luego se devuelve el conjunto de resultados. Construir la tabla temporal ya lleva mucho tiempo, no quisiera una vista que también intente adivinar qué índices se necesitan. Lo que trae a colación el segundo punto, que es que MySQL actualmente no ofrece un método para especificar qué índices usar para una Vista, entonces, ¿cómo sabe qué campos necesitan indexarse? ¿Se adivina en función de su consulta?

Puede considerar usar una Tabla temporal porque entonces puede especificar índices en los campos de la tabla temporal. Sin embargo, por experiencia esto tiende a ser muy, muy lento.

Si todo lo que contiene esta vista es un SELECCIONAR TODO DE tabla1, tabla2, tabla3; entonces tendría que preguntar por qué esta consulta debe estar en una vista. Si por alguna razón es absolutamente necesario, es posible que desee utilizar un procedimiento almacenado para encapsular la consulta, ya que podrá obtener un rendimiento optimizado mientras mantiene el beneficio de una llamada más simple a la base de datos para el conjunto de resultados.

Otros consejos

Lo he examinado más a fondo y he perdido un punto clave de información :( Mi consulta de vista en realidad tiene una unión con otra tabla. Esto está causando que la vista use el algoritmo TABLA TEMPORAL en lugar del algoritmo MERGE.

El algoritmo TABLA TEMPORAL no permite el uso de índices en las tablas subyacentes.

¡Esto parece ser un error en MySQL y se informó en 2006, pero no parece que se haya resuelto en 2009! http://forums.mysql.com/read.php?100,56681, 56681

Parece que voy a tener que volver a escribir la consulta como una combinación externa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top