mysql优化(索引失效)

where 子句部分和最左原则对照,看是否生效的口诀:带头大哥不能死,中间兄弟不能断

简单来说就是:MySQL 在决定是否要应用索引时,会对照 SQL 语句中要过滤的字段的顺序和索引中字段的顺序。那么具体是怎么对照的呢?请看下面的细节:

所有有过滤功能的子句都会将相关字段去和索引尝试匹配:

- ON 子句
- WHERE 子句
- GROUP BY 子句
- HAVING 子句
- LIMIT 子句

1.创建联合索引:

按照这个索引创建方式,索引中字段的顺序是:age、deptid、NAME
CREATE INDEX idx_age_deptid_name ON emp(age, deptid, NAME);

mysql优化(索引失效)_第1张图片

 mysql优化(索引失效)_第2张图片

mysql优化(索引失效)_第3张图片 

 

单值索引和复合索引的选择

在实际开发中,一个数据库表包含多个字段,其中有若干个字段有很大几率出现在 where 或其他有可能触发索引的子句中。那么我们倾向于创建『复合索引』,而不是『单值索引』。

因为一个复合索引能够涵盖到其中包含的每个字段;而给每一个字段分别创建单值索引会生成更多的索引表,增加切换、磁盘存储、I/O 等方面的开销。

如下我们修改字段的查询顺序:

mysql优化(索引失效)_第4张图片

看上去索引是生效的,但是很明显顺序不一致,不满足最左原则,本来是不应该生效的:

- 查询顺序:deptId、name、age
- 索引顺序:age、deptid、NAME

但是为什么索引生效了呢?其实原本是不应该生效的,但是此时是 MySQL 的 SQL 优化器调整了解析树,使查询字段符合了索引顺序,这才让索引生效了。

但是尽管优化器能够帮助我们进行调整,但是调整本身也需要付出代价,产生系统开销。所以我们开发时还是要尽量和索引中字段顺序一致。

 mysql优化(索引失效)_第5张图片

 

索引没有生效!

但是很奇怪,deptId 这个字段明明是在索引中呀?这是因为本次查询没有满足最左原则。

在索引中,age 字段在最左边,现在查询的 deptId 作为第一个查询的字段不是 age,这就违背了最左原则。

为什么 MySQL 会如此执着于『最左』字段?

这是因为生成索引所在的 B+Tree 的时候,需要对索引值进行排序。
那么如果我们指定的是联合索引,那么将涉及到多个字段的排序。
例如:age、deptId、name这三个字段要排序的话,肯定优先根据 age 排序;
然后在 age 值有相同数据时对 deptId 排序,以此类推。

所以我们在实际查询时,需要首先根据 age 字段在索引 B+Tree 中进行二分法查找。
此时如果没有提供 age 字段,那将无法使用索引。

mysql优化(索引失效)_第6张图片

 2.结论:

要遵循最左原则,查询字段中至少要有索引中的最左字段作为过滤条件存在。
而且就最左原则本身来说,它要求索引最左字段在查询顺序中也最左。
只不过只要最左字段出现,优化器会帮我们调整到查询顺序中的最左。
而且还有一个要求是:中间不能断。中间一旦断开,后面的就都无法使用索引了

mysql优化(索引失效)_第7张图片

         

3.索引失效的其他情况:

mysql优化(索引失效)_第8张图片

key_len 的计算角度:age 字段贡献了 5,deptId 字段贡献了 5,
而 name 字段如果应用了索引,那么它应该贡献 63。
但是最终 key_len 是 10,说明索引生效的字段是 age 和 deptId

 mysql优化(索引失效)_第9张图片

 

- type 的取值角度:range,说明查询的类型是范围查询,在当前 SQL 语句中 deptId 做的就是范围查询
- 解决方案角度:把 deptId 放在后面,三个字段的索引就都生效了。
               说明范围查询并不是祸害自己,而是祸害后面的查询条件。

4.结论


- 注意点1:创建索引时应该把容易做范围查询的字段往后放
- 注意点2:实际编写 SQL 语句时,做范围查询的字段参照索引中的顺序,也是往后放

mysql优化(索引失效)_第10张图片

 

查看分析结果,发现 key_len 是 68,68 = 63 + 5。
说明生效的字段是 name、age,deptId 还是没有生效。
这就说明范围查询即使放在后面也只有第一个生效。

②在 where 子句条件中使用函数

mysql优化(索引失效)_第11张图片

结论:使用了 left() 函数导致了索引失效。

 

③不等于:所有的不等于操作都会导致索引失效

- !=
- <>
- not

④like:并不是所有的查询都会导致索引失效

- 生效:左边是确定的
- 失效:左边不确定

⑤涉及类型转换:给查询的条件传入的参数和原本的类型不一致,不一定会导致索引失效

- 失效情况举例:让 char 类型的字段和 123 比较
- 有效情况举例:让 int 类型的字段和 '123' 比较

5.一个小练习:

mysql优化(索引失效)_第12张图片

总结:

- 对于单键索引,尽量选择**过滤性更好的字段**来创建索引(例如:手机号,邮件,身份证)。
  这样更容易过滤掉大量数据,为后面操作减轻负担。

- 在选择组合索引的时候,过滤性最好的字段在索引字段顺序中,位置越靠前越好。
  这样可以更早过滤掉大量数据。

- 选择组合索引时,尽量包含where中更多字段的索引,
  这是为了让 where 条件尽可能更多的享受到索引带来的福利。

- 组合索引出现范围查询时,尽量把这个字段放在索引次序的最后面

- 尽量避免造成索引失效的情况

 

你可能感兴趣的:(mysql,mysql,oracle,sql)