Problema di ottimizzazione: chiavi raggruppate composte, condizioni flag e unione-indice


11

Tre tavoli:

product: con colonne: ( a, g, ...a_lot_more... )

a: PK, clustered
g: bit-column

main: con colonne: ( c, f, a, b, ...a_lot_more... )

c: PK, clustered
f: bit-column
(a, b): UQ 

lookup con colonne: ( a, b, c, i )

(a, b): PK, clustered
a: FK to product(a)
c: UQ, FK to main(c)
i: bit-column

Non riesco a trovare buoni indici per il join:

FROM  
    product
  JOIN 
    lookup
      ON  lookup.a = product.a  
  JOIN
    main
      ON  main.c = lookup.c 
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

Ho provato un indice di copertura product (g, a, ...)e viene utilizzato ma non con risultati spettacolari.

Alcune combinazioni di indici nella lookuptabella producono piani di esecuzione con fusione degli indici, con un leggero guadagno di efficienza rispetto al piano precedente.

C'è qualche combinazione ovvia che mi manca?

Potrebbe essere utile una riprogettazione della struttura?

Il DBMS è MySQL 5.5 e tutte le tabelle utilizzano InnoDB.


Tabella dimensioni:

product: 67K   ,  g applied:    64K 

main:   420K   ,  f applied:   190K

lookup:  12M   ,  b,i applied:  67K 

Prova a spostare i predicati del filtro nei join e vedi se l'ottimizzatore fa qualcosa di sensato. Ho visto l'ottimizzatore di SQL Server fallire su quello prima.
ConcernedOfTunbridgeWells

Sembra un prodotto cartesiano perché non vedo nulla che si unisce alla tabella dei prodotti. O mi sono perso qualcosa ???
RolandoMySQLDBA,

@RolandoMySQLDBA: hai ragione. Correggerò la domanda.
ypercubeᵀᴹ

Risposte:


3

Questo mi fa male ...

Prima ho dovuto usare le tabelle temporanee con InnoDB. Caricali con i filtri, crea un indice, unisciti a queste tabelle temporanee.

Il problema, secondo me, è se InnoDB ha solo l'algoritmo Nested Join: gli ottimizzatori di query RDBMS cresciuti hanno più da usare. Questo si basa sul tentativo di eseguire i carichi di tipo Data Warehouse su InnoDB.

Le tabelle temporanee trascinano la complessità complessiva al di sotto del livello di Query Optimizer di MySQL ...


Grazie, ci proverò. Il numero o le righe (dopo l'applicazione dei criteri non sono così grandi, rispettivamente 64K, 67K, 190K). Forse dovrei provare a sbarazzarmi di una delle tre tabelle ( main) denormalizzando i dati in lookup?
ypercubeᵀᴹ

1
@ypercube: la denormalizzazione renderà le righe più ampie, una densità di pagina inferiore = altri problemi
gbn,

3

Sembra un prodotto cartesiano. Ripeti i criteri JOIN

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON  main.c = lookup.c 
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

SUGGERIMENTI ALTERNATIVI

Questo può sembrare poco ortodosso e probabilmente puzza di SQL Anitpattern, ma qui va ...

FROM  
    product
JOIN 
    (
        SELECT * FROM lookup
        WHERE i=1 AND b=17
    ) lookup ON product.a = lookup.a  
JOIN
   main ON main.c = lookup.c 
WHERE 
    product.g = 1 AND main.f = 1

Non ho spostato product.g = 1e main.f = 1nelle sottoquery perché sono campi di bit e al momento eseguirò solo una scansione della tabella. Anche se i campi di bit fossero indici, lo Strumento per ottimizzare le query ignorerebbe semplicemente tale indice.

Ovviamente, puoi passare SELECT * FROM lookupa SELECT a FROM lookupse il tuo SELECT non ha bisogno di nullalookup

Forse coinvolgere a, b nel JOIN tra ricerca e principale se questo ha senso

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON  main.a = lookup.a AND main.b = lookup.b
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

o rimetti c e unisciti su tre colonne (indice sulle tre colonne in maine lookup)

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON main.a = lookup.a
      AND main.b = lookup.b
      AND main.c = lookup.c
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

Thnx. Piano EXPLAIN diverso, ma prestazioni simili.
ypercubeᵀᴹ

Qual è la cardinalità di main.fe product.g??? Se la cardinalità di main.fe product.gper il valore è 1 è inferiore al 5% delle righe della tabella, un indice su main.fe product.gpuò essere giustificabile.
RolandoMySQLDBA

Non importa, sono già indicizzati. Se la cardinalità di main.fe product.gè 2, è possibile abbandonare quegli indici.
RolandoMySQLDBA

Modificata la domanda con le dimensioni della tabella e le righe utilizzate (dopo aver applicato le condizioni).
ypercubeᵀᴹ

Ho aggiornato la mia domanda, suggerimento ISCRIVITI a a, b anziché a c. Vedi se questo rende un piano EXPLAIN diverso
RolandoMySQLDBA il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.