Использование индекса MySQL при соединении - PullRequest
0 голосов
/ 08 июня 2018

Я знаю, что есть несколько вопросов, похожих на этот, но те, которые я нашел, не имеют прямого отношения к моей проблеме.

Некоторый начальный контекст: у меня есть таблица фактов, называемая ft_booking, с записями около 10 мм.У меня есть измерение, называемое dm_date, с примерно 11k записями, которые являются датами.Эти таблицы связаны, как обычно, через внешние ключи.В таблице ft_booking есть 3 внешних ключа даты, один для посадки, один для бронирования и другой для отмены.Все столбцы имеют одно и то же определение, и количество отдельных записей для каждого из них одинаково (в диапазоне от 2,5 до 3 000 различных значений в каждом столбце).

Вот и я:

EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_booking
WHERE date (db.date) = '2018-05-05'

enter image description here

Как видите, при бронировании таблицы используется индекс, и запрос выполняется очень быстро, хотя в моем фильтре я использую дату() функция.Для краткости я просто скажу, что то же самое происходит с использованием столбца fk_date_boarding.Но, проверьте это:

EXPLAIN SELECT
*
FROM dw.ft_booking b
LEFT JOIN dw.dm_date db ON db.sk_date = b.fk_date_cancellation
WHERE date (db.date) = '2018-05-05';

enter image description here

По какой-то таинственной причине планировщик решает не использовать индекс.Теперь я понимаю, что использование некоторой функции над столбцом заставляет базу данных выполнить полное сканирование таблицы, чтобы можно было применить эту функцию к столбцу, минуя индекс.Но, в этом случае, функция находится не над фактическим столбцом внешнего ключа, где должен происходить поиск в таблице бронирования.

Если я уберу функцию date (), индекс будет использоваться в любом из этих столбцов, как и ожидалось.Тогда можно сказать: «Ну, почему бы вам просто не избавиться от функции date ()?»- Я использую метабазу, интерфейс, который позволяет пользователям использовать графический интерфейс для создания запросов, не зная MySQL, и одно из текущих ограничений этого инструмента заключается в том, что он всегда использует функцию date () при построении запросов, не написанных непосредственно вMySQL - следовательно, у меня нет возможности удалить функцию в запросах, которые я выполняю.

Актуальный вопрос: почему MySQL использует индекс в первых двух случаях, но не во втором, учитываяколичество различных значений одинаково для всех столбцов, и у них есть точное определение smae, кроме имени?Я что-то здесь упускаю?

РЕДАКТИРОВАТЬ: Здесь - это CREATE-статус каждой таблицы.Есть еще несколько, но нам просто нужны здесь таблицы ft_booking и dm_date (первые две таблицы файла).

1 Ответ

0 голосов
/ 09 июня 2018

Вы «скрываете date в вызове функции».Если db.date объявлено DATE, тогда

    date (db.date) = '2018-05-05'

может быть просто

    db.date = '2018-05-05'

Если db.date объявлено DATETIME, то изменить на

        db.date >= '2018-05-05'
    AND db.date  < '2018-05-05' + INTERVAL 1 DAY

В любом случае, убедитесь, что есть индекс db.date.

Если под «У меня есть измерение с именем dm_date», вы имеете в виду, что вы построили таблицу измерений для хранения только дат,и тогда вы JOINing подойдете к основному столу с некоторыми id, ... Грубо говоря, не делайте этого! Не нормализуйте "непрерывные" вещи, такие как DATE,DATETIME, FLOAT или другие числовые значения.

Если вам необходимо обсудить это дополнительно, укажите SHOW CREATE TABLE для соответствующей таблицы (таблиц).(И, пожалуйста, используйте текст, а не снимки экрана.)

Почему ??

Простой ответ заключается в том, что оптимизатор не знает, как распознать какую-либо функцию.Возможно это могло бы;возможно, так и должно быть.Но это не так.Возможно, ответ заключается в нежелании видеть, как будет использоваться результат функции ... по сравнению с DATE?против DATETIME?используется как строка?Другой?

Тем не менее, я полагаю, что реальным фактором снижения производительности является наличие dm_date, а не индексация и использование даты в основной таблице.

Кроме того, главная таблица больше еедолжно быть!fk_date_booking является 4-байтовым INT SIGNED вместо 3-байтового DATE.

...