Domanda

Sto cercando di ottimizzare una query che utilizza una vista in MySQL 5.1. Sembra che anche se seleziono 1 colonna dalla vista esegua sempre una scansione completa della tabella. È questo il comportamento previsto?

La vista è solo un SELEZIONA " Tutte le colonne da queste tabelle - NON * " per le tabelle che ho specificato nella prima query di seguito.

Questo è il mio spiegazione dell'output di quando seleziono la colonna indicizzata PromotionID dalla query che costituisce la vista. Come puoi vedere, è molto diverso dall'output nella 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)

L'output quando seleziono la stessa cosa ma dalla 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)
È stato utile?

Soluzione

Le viste in MySQL non sono indicizzate, quindi per loro stessa natura richiedono una scansione completa ogni volta che si accede. In generale, ciò rende Views davvero utile solo per le situazioni in cui si ha una query statica abbastanza complessa che restituisce un set di risultati ridotto e si prevede di afferrare l'intero set di risultati ogni volta.

Modifica: Naturalmente le Viste utilizzeranno gli indici sulle tabelle sottostanti in modo che la Vista stessa sia ottimizzata (altrimenti non avrebbero alcun senso da usare) ma perché non ci sono indici su una vista non è possibile ottimizzare una query WHERE sulla vista.

La costruzione di indici per Views sarebbe comunque costosa perché, anche se non ho provato a profilare alcuna Views, sono abbastanza certo che una tabella temporanea è costruita dietro le quinte e quindi il set di risultati è tornato. Ci vuole già un sacco di tempo per costruire la tabella temporanea, non vorrei una vista che provasse anche a indovinare quali indici sono necessari. Il che fa apparire il secondo punto, ovvero che MySQL non offre attualmente un metodo per specificare quali indici utilizzare per una vista, quindi come fa a sapere quali campi devono essere indicizzati? Indovina in base alla tua query?

Puoi prendere in considerazione l'utilizzo di una Tabella temporanea perché quindi è possibile specificare gli indici sui campi nella tabella temporanea. Tuttavia, per esperienza, questo tende ad essere molto, molto lento.

Se tutta questa vista contiene è SELEZIONA TUTTO DA tabella1, tabella2, tabella3; allora dovrei chiedere perché questa query deve essere in una vista a tutti? Se per qualche motivo è assolutamente necessario, è possibile utilizzare una procedura memorizzata per incapsulare la query poiché sarà quindi possibile ottenere prestazioni ottimizzate mantenendo il vantaggio di una chiamata più semplice al database per il set di risultati.

Altri suggerimenti

Ho approfondito la questione e ho perso un punto chiave delle informazioni :( La mia query di visualizzazione in realtà ha un'unione con un'altra tabella. Questo sta facendo sì che la vista usi l'algoritmo TEMPORARY TABLE invece dell'algoritmo MERGE.

L'algoritmo TEMPORARY TABLE non consente l'uso di indici nelle tabelle sottostanti.

Questo sembra essere un bug in MySQL ed è stato segnalato nel 2006, ma non sembra che sia stato risolto nel 2009! http://forums.mysql.com/read.php?100.56681, 56681

Sembra che dovrò riscrivere la query come join esterno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top