Problema de optimización: claves agrupadas compuestas, condiciones de marca y fusión de índice


11

Tres mesas:

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

a: PK, clustered
g: bit-column

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

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

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

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

No puedo encontrar buenos índices para la unión:

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

Intenté un índice de cobertura product (g, a, ...)y se usa pero no con resultados espectaculares.

Algunas combinaciones de índices en la lookuptabla producen planes de ejecución con fusión de índice, con una ligera ganancia de eficiencia sobre el plan anterior.

¿Hay alguna combinación obvia que me estoy perdiendo?

¿Podría ayudar un rediseño de la estructura?

El DBMS es MySQL 5.5 y todas las tablas están usando InnoDB.


Tamaños de mesa:

product: 67K   ,  g applied:    64K 

main:   420K   ,  f applied:   190K

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

Intente mover los predicados de filtro a las uniones y vea si el optimizador hace algo sensato con eso. He visto el optimizador de SQL Server fallar en eso antes.
ConcernedOfTunbridgeWells

Parece un producto cartesiano porque no veo nada uniéndose desde la tabla de productos. ¿O me perdí algo?
RolandoMySQLDBA

@RolandoMySQLDBA: Tienes razón. Corregiré la consulta.
ypercubeᵀᴹ

Respuestas:


3

Esto me duele ...

He tenido que usar tablas temporales con InnoDB antes. Cárguelos con filtros, cree un índice, únase a esta tabla temporal.

Creo que el problema es que si InnoDB solo tiene un algoritmo de unión anidada: los optimizadores de consultas RDBMS adultos tienen más para usar. Esto se basa en intentar ejecutar cargas de tipo Data Warehouse en InnoDB.

Las tablas temporales arrastran la complejidad general por el nivel del optimizador de consultas MySQL ...


Thnx, lo intentaré. El número o las filas (después de aplicar los criterios no son tan grandes, 64K, 67K, 190K respectivamente). ¿Quizás debería tratar de deshacerme de una de las tres tablas ( main) desnormalizando datos en lookup?
ypercubeᵀᴹ

1
@ypercube: denormalising ampliará las filas, disminuirá la densidad de la página = otros problemas
gbn

3

Parece un producto cartesiano. Rehacer los criterios de 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

SUGERENCIA ALTERNATIVA

Esto puede parecer poco ortodoxo y probablemente huele a SQL Anitpattern, pero aquí 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

No moví el product.g = 1y main.f = 1a las subconsultas porque son campos de bits y solo haré un escaneo de la tabla en el punto. Incluso si los campos de bits fueran índices, el Optimizador de consultas simplemente ignoraría dicho índice.

Por supuesto, puede cambiar SELECT * FROM lookupa SELECT a FROM lookupsi su SELECT no necesita nada delookup

Quizás implique a, b en la UNIÓN entre búsqueda y principal si esto tiene sentido

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 vuelva a colocar c y únase en tres columnas (Indice las tres columnas en mainy 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. Diferente plan EXPLICAR, pero rendimiento similar.
ypercubeᵀᴹ

¿Cuál es la cardinalidad de la main.fy product.g??? Si la cardinalidad de main.fy product.gpara el valor es 1 es inferior al 5% de las filas de la tabla, un índice en main.fy product.gpuede ser justificable.
RolandoMySQLDBA

No importa, ya están indexados. Si la cardinalidad de main.fy product.ges 2, podría deshacerse de esos índices.
RolandoMySQLDBA

Editó la pregunta con los tamaños de tabla y las filas utilizadas (después de aplicar las condiciones).
ypercubeᵀᴹ

Actualicé mi pregunta, sugerencia UNIRSE en a, b en lugar de c. Vea si eso hace un plan EXPLICAR diferente
RolandoMySQLDBA
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.