【老叶观点】除了常见的建议外,还有几个要点: 7.1、超过20个长度的字符串列,最好创建前缀索引而非整列索引(例如:ALTER TABLE t1 ADD INDEX(user(20))),可以有效提高索引利用率,不过它的缺点是对这个列排序时用不到前缀索引。前缀索引的长度可以基于对该字段的统计得出,一般略大于平均长度一点就可以了。 7.2、定期用 pt-duplicate-key-checker 工具检查并删除重复的索引。比如 index idx1(a, b) 索引已经涵盖了 index idx2(a),就可以删除 idx2 索引了。 7.3、有多字段联合索引时,WHERE中过滤条件的字段顺序无需和索引一致,但如果有排序、分组则就必须一致了。 比如有联合索引 idx1(a, b, c),那么下面的SQL都可以完整用到索引: ~~~ SELECT ... WHERE b = ? AND c = ? AND a = ?;  --注意到,WHERE中字段顺序并没有和索引字段顺序一致 SELECT ... WHERE b = ? AND a = ? AND c = ?; SELECT ... WHERE a = ? AND b IN (?, ?) AND c = ?; SELECT ... WHERE a = ? AND b = ? ORDER BY c; SELECT ... WHERE a = ? AND b IN (?, ?) ORDER BY c; SELECT ... WHERE a = ? ORDER BY b, c; SELECT ... ORDER BY a, b, c;  -- 可利用联合索引完成排序 ~~~ 而下面几个SQL则只能用到部分索引,或者可利用到ICP特性: ~~~ SELECT ... WHERE b = ? AND a = ?; -- 只能用到 (a, b) 部分 SELECT ... WHERE a IN (?, ?) AND b = ?; -- EXPLAIN显示只用到 (a, b) 部分索引,同时有ICP SELECT ... WHERE (a BETWEEN ? AND ?) AND b = ?; -- EXPLAIN显示只用到 (a, b) 部分索引,同时有ICP SELECT ... WHERE a = ? AND b IN (?, ?); -- EXPLAIN显示只用到 (a, b) 部分索引,同时有ICP SELECT ... WHERE a = ? AND (b BETWEEN ? AND ?) AND c = ?; -- EXPLAIN显示用到 (a, b, c) 整个索引,同时有ICP SELECT ... WHERE a = ? AND c = ?; -- EXPLAIN显示只用到 (a) 部分索引,同时有ICP SELECT ... WHERE a = ? AND c >= ?; -- EXPLAIN显示只用到 (a) 部分索引,同时有ICP ICP(index condition pushdown)是MySQL 5.6的新特性,其机制会让索引的其他部分也参与过滤,减少引擎层和server层之间的数据传输和回表请求,通常情况下可大幅提升查询效率。 ~~~ 下面的几个SQL完全用不到该索引: ~~~ SELECT ... WHERE b = ?; SELECT ... WHERE b = ? AND c = ?; SELECT ... WHERE b = ? AND c = ?; SELECT ... ORDER BY b; SELECT ... ORDER BY b, a; ~~~ 从上面的几个例子就能看的出来,以往强调的WHERE条件字段顺序要和索引顺序一致才能使用索引的 “常识性误导” 无需严格遵守。 此外,有些时候查询优化器指定的索引或执行计划可能并不是最优的,可以手工指定最优索引,或者修改session级的 [optimizer_switch](http://dev.mysql.com/doc/refman/5.6/en/switchable-optimizations.html) 选项,关闭某些导致效果反而更差的特性(比如index merge通常是好事,但也遇到过用上index merge后反而更差的,这时候要么强制指定其中一个索引,要么可以临时关闭 index merge 特性)。