Задача оптимизации: составные кластерные ключи, условия флага и слияние индекса

11

Три стола:

product: с колонками: ( a, g, ...a_lot_more... )

a: PK, clustered
g: bit-column

main: с колонками: ( c, f, a, b, ...a_lot_more... )

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

lookup с колоннами: ( a, b, c, i )

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

Я не могу найти хорошие индексы для объединения:

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

Я примерил индекс покрытия, product (g, a, ...)и он используется, но не с впечатляющими результатами.

Некоторые комбинации индексов в lookupтаблице создают планы выполнения с объединением индексов с небольшим приростом эффективности по сравнению с предыдущим планом.

Есть ли какая-то очевидная комбинация, которую мне не хватает?

Может ли помочь реструктуризация конструкции?

СУБД - MySQL 5.5, и все таблицы используют InnoDB.


Размеры стола:

product: 67K   ,  g applied:    64K 

main:   420K   ,  f applied:   190K

lookup:  12M   ,  b,i applied:  67K 
ypercubeᵀᴹ
источник
Попробуйте переместить предикаты фильтра в объединения и посмотрите, не делает ли оптимизатор что-то разумное с этим. Я уже видел сбой оптимизатора SQL Server на этом раньше.
ConcernedOfTunbridgeWells
Выглядит как декартово произведение, потому что я не вижу ничего, ЧТО СОЕДИНЯЕТСЯ из таблицы товаров. Или я что то пропустил ???
RolandoMySQLDBA
@RolandoMySQLDBA: Вы правы. Я исправлю запрос.
ypercubeᵀᴹ

Ответы:

3

Это причиняет мне боль ...

Я должен был использовать временные таблицы с InnoDB раньше. Загрузите их с фильтрами, создайте индекс, присоединитесь к этой временной таблице.

Я считаю, что проблема заключается в том, что InnoDB имеет только алгоритм Nested Join: взрослые оптимизаторы запросов к RDBMS могут использовать больше. Это основано на попытке запустить загрузку типов хранилища данных на InnoDB.

Временные таблицы тянут общую сложность до уровня оптимизатора запросов MySQL ...

ГБН
источник
Спасибо, я попробую это. Число или ряды (после применения критериев они не такие большие, 64К, 67К, 190К соответственно). Может быть, я должен попытаться избавиться от одной из трех таблиц ( main) путем денормализации данных в lookup?
ypercubeᵀᴹ
1
@ypercube: денормализация сделает строки шире, более низкая плотность страниц = другие проблемы
2012 г.
3

Это похоже на декартово произведение. Повторите критерии присоединения

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

АЛЬТЕРНАТИВНОЕ ПРЕДЛОЖЕНИЕ

Это может показаться неортодоксальным и, вероятно, пахнет SQL Anitpattern, но здесь все идет ...

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

Я не перемещал product.g = 1и main.f = 1в подзапросы, потому что они являются битовыми полями и просто будут выполнять сканирование таблицы в этой точке. Даже если бы битовые поля были индексами, Оптимизатор запросов просто проигнорировал бы такой индекс.

Конечно, вы могли бы изменить , SELECT * FROM lookupчтобы , SELECT a FROM lookupесли ваш ВЫБРАТЬ не нужно ничего отlookup

Возможно, включите a, b в JOIN между lookup и main, если это имеет смысл

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

или вставьте обратно c и объедините три столбца (индекс по трем столбцам в mainи 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
RolandoMySQLDBA
источник
Thnx. Различный план EXPLAIN, но похожая производительность.
ypercubeᵀᴹ
Какая мощность main.fи product.g??? Если мощность main.fи product.gдля значения 1 составляет менее 5% строк таблицы, индекс на main.fи product.gможет быть оправданным.
RolandoMySQLDBA
Неважно, они уже проиндексированы. Если мощность main.fи product.g2, то вы могли бы угробить эти индексы.
RolandoMySQLDBA
Отредактировал вопрос с размерами таблицы и используемыми строками (после применения условий).
ypercubeᵀᴹ
Я обновил свой вопрос, предложив присоединиться к a, b вместо c. Смотрите, если это делает другой план EXPLAIN
RolandoMySQLDBA