Как мне сказать оптимизатору MySQL использовать индекс для производной таблицы? - PullRequest
6 голосов
/ 18 января 2012

Предположим, у вас есть запрос, подобный этому ...

SELECT T.TaskID, T.TaskName, TAU.AssignedUsers
FROM `tasks` T
    LEFT OUTER JOIN (
        SELECT TaskID, GROUP_CONCAT(U.FirstName, ' ',
            U.LastName SEPARATOR ', ') AS AssignedUsers
        FROM `tasks_assigned_users` TAU
            INNER JOIN `users` U ON (TAU.UserID=U.UserID)
        GROUP BY TaskID
    ) TAU ON (T.TaskID=TAU.TaskID)

Для выполнения одной задачи может быть назначено несколько человек.Цель этого запроса - показать по одной строке для каждой задачи, но с людьми, назначенными для этой задачи, в одном столбце

Теперь ... предположим, что у вас настроены правильные индексы на tasks, usersи tasks_assigned_users.Оптимизатор MySQL по-прежнему не будет использовать индекс TaskID при присоединении tasks к производной таблице.WTF?!?!?

Итак, мой вопрос ... как сделать так, чтобы этот запрос использовал индекс для tasks_assigned_users.TaskID?Временные таблицы не работают, поэтому, если это единственное решение ... MySQL Optimizer глупо.

Используемые индексы:

  • tasks
    • PRIMARY - TaskID
  • пользователи
    • ПЕРВИЧНЫЙ - UserID
  • tasks_assigned_users
    • ПЕРВИЧНЫЙ - (TaskID, UserID)
    • Дополнительный индекс UNIQUE - (UserID, TaskID)

EDIT: Кроме того, эта страница говорит, что производные таблицы выполнены/ материализован до того, как произойдет соединение.Почему бы не использовать ключи повторно для объединения?

РЕДАКТИРОВАТЬ 2: Оптимизатор MySQL не позволит помещать подсказки индекса в производные таблицы (предположительно потому, чтонет индексов для производных таблиц)

РЕДАКТИРОВАТЬ 3: Вот действительно хороший пост в блоге об этом: http://venublog.com/2010/03/06/how-to-improve-subqueries-derived-tables-performance/ Обратите внимание, что дело № 2 - это решение, которое я ищудля, но похоже, что MySQL не поддерживает это в настоящее время.: (

РЕДАКТИРОВАТЬ 4: Только что найдено this : "Начиная с MySQL 5.6.3, оптимизатор более эффективно обрабатывает подзапросы в предложении FROM (то есть, является производнымтаблицы): ... Во время выполнения запроса оптимизатор может добавить индекс в производную таблицу, чтобы ускорить извлечение строки из нее. "Кажется многообещающим ...

Ответы [ 3 ]

4 голосов
/ 19 января 2012

Существует решение для этого в MySQL Server 5.6 - предварительный выпуск (на момент написания этой статьи).

http://dev.mysql.com/doc/refman/5.6/en/from-clause-subquery-optimization.html

Хотя я не уверен, будет ли оптимизатор MySQL повторно использовать уже существующие индексы, когда он «добавляет индексы в производную таблицу»

Рассмотрим следующий запрос:

ВЫБРАТЬ * ОТ t1 ПРИСОЕДИНЯЙТЕСЬ (ВЫБЕРИТЕ * ОТ t2), КАК ИДЕНТИФИЦИРОВАНО НА ВЫХОДЕ t1f1 = производная_t2.f1;

Документация гласит: «Оптимизатор создает индекс по столбцу f1 из производного_t2, если это позволит использовать доступ ref для плана выполнения с наименьшими затратами».

Хорошо, это замечательно, но оптимизатор повторно использует индексы из t2? Другими словами, что, если для t2.f1 существует индекс? Этот индекс используется повторно или оптимизатор повторно создает этот индекс для производной таблицы? Кто знает?

РЕДАКТИРОВАТЬ: Лучшее решение до MySQL 5.6 - создать временную таблицу, создать индекс для этой таблицы, а затем выполнить запрос SELECT для временной таблицы.

2 голосов
/ 18 января 2012

Проблема, которую я вижу, состоит в том, что при выполнении подзапроса нет базовой индексированной таблицы.Если у вас есть представление, я бы в конце сделал группировку, примерно так:

SELECT T.TaskID, T.TaskName, GROUP_CONCAT(U.FirstName, ' ', U.LastName SEPARATOR ', ') AS AssignedUsers
FROM `tasks` T
    LEFT OUTER JOIN  `tasks_assigned_users` TAU ON (T.TaskID=TAU.TaskID)
    INNER JOIN `users` U ON (TAU.UserID=U.UserID)
GROUP BY T.TaskID, T.TaskName
1 голос
/ 18 января 2012

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

...