如何告诉MySQL Optimizer在派生表上使用索引?

时间:2012-01-18 19:29:57

标签: mysql sql join derived-table optimization

假设您有这样的查询...

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)

可以将多个人分配给给定任务。此查询的目的是为每个任务显示一行,但将人员分配给单个列中的任务

现在......假设您在tasksuserstasks_assigned_users上设置了正确的索引。将tasks加入派生表时,MySQL Optimizer仍然不会使用TaskID索引。 WTF?!?!?

所以,我的问题是......如何使这个查询使用tasks_assigned_users.TaskID上的索引?临时表是蹩脚的,所以如果这是唯一的解决方案...... MySQL优化器是愚蠢的。

使用的索引:

  • 任务
    • PRIMARY - TaskID
  • 用户
    • PRIMARY - UserID
  • tasks_assigned_users
    • PRIMARY - (TaskID,UserID)
    • 附加索引UNIQUE - (UserID,TaskID)

编辑:此外,this page表示派生表在连接发生之前执行/实现。为什么不重复使用密钥来执行连接?

编辑2: MySQL优化器不允许您将index hints放在派生表上(可能是因为派生表上没有索引)

编辑3:以下是一篇非常好的博客文章:http://venublog.com/2010/03/06/how-to-improve-subqueries-derived-tables-performance/请注意,案例#2是我正在寻找的解决方案,但似乎MySQL不支持这个在这个时候。 :(

编辑4:刚刚找到this:“从MySQL 5.6.3开始,优化器更有效地处理FROM子句中的子查询(即派生表):...在查询执行期间,优化器可以向派生表添加索引,以加速从中检索行。“似乎很有希望......

3 个答案:

答案 0 :(得分:4)

MySQL Server 5.6中有一个解决方案 - 预览版本(撰写本文时)。

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

虽然,我不确定MySQL Optimizer是否会在“将索引添加到派生表”时重用已存在的索引

考虑以下问题:

SELECT * FROM t1   JOIN(SELECT * FROM t2)AS derived_t2 ON t1.f1 = derived_t2.f1;

文档说:“如果这样做允许使用ref访问来获得最低成本的执行计划,那么优化器会从derived_t2构建一个列f1的索引。”

好的,那很好,但优化器是否重用了t2的索引?换句话说,如果t2.f1存在索引怎么办?是否重新使用此索引,或者优化程序是否为派生表重新创建此索引?谁知道?

编辑: MySQL 5.6之前的最佳解决方案是创建临时表,在该表上创建索引,然后在临时表上运行SELECT查询。

答案 1 :(得分:2)

我看到的问题是,通过执行子查询,没有底层索引表。 如果你有表演,我会在最后进行分组,如下所示:

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

答案 2 :(得分:1)

我害怕,这是not possible。您必须创建临时表或视图才能使用索引。