另外此bug引发的另一个问题是,由于使用了LIMIT语句,导致选择的INDEX不是最优的INDEX。

  1. SET optimizer_trace="enabled=on";

执行上面的查询语句,可以看到optimizer trace的输出结果如下,请注意里面重点部位的注释(以’//’开头部分):

make_join_select函数中有下面一段逻辑:

  1. if (!tab->const_keys.is_clear_all() && // 有依赖于常量的索引条件表达式
  2. i == join->const_tables && // 是第一个非常量表
  3. (join->unit->select_limit_cnt <
  4. tab->position->records_read) &&
  5. !(join->select_options & OPTION_FOUND_ROWS)) // 没有SQL_CALC_FOUND_ROWS
  6. ...
  7. // 检查是否有RANGE scan可以使用
  8. if ((recheck_reason != DONT_RECHECK) &&
  9. sel->test_quick_select(thd, usable_keys,
  10. used_tables & ~tab->table->map,
  11. (join->select_options &
  12. join->unit->select_limit_cnt),
  13. false, // don't force quick range
  14. interesting_order) < 0)
  15. {
  16. 这里usable_keys是描述可以用来对ORDER BY列进行索引排序的可能的所有索引的MAP。上面的函数会查找这些可用的索引是否可以进行更高效RANGE
  17. 扫描。但是通过问题query的条件表达式,这里没有找到对应的RANGE扫描,所以最后的执行计划输出只是使用了一个COVERING index.

可以看到最终效果是:

  1. EXPLAIN SELECT id FROM t1 WHERE a<3 AND b IN (1, 13) AND c>=3 ORDER BY c DESC LIMIT 2;
  2. 1 SIMPLE t1 range iabc,ic iabc 5 NULL 4 Using index condition; Using filesort