MySQL 索引一般是被用于提升 WHERE 条件的数据行匹配时的搜索速度,在索引的使用过程当中,存在一些使用细节和注意事项。javascript
原文地址:服务端指南 数据存储篇 | MySQL(04)索引使用的注意事项
博客地址:blog.720ui.com/java
不要在列上使用函数,这将致使索引失效而进行全表扫描。mysql
select * from news where year(publish_time) < 2017复制代码
为了使用索引,防止执行全表扫描,能够进行改造。sql
select * from news where publish_time < '2017-01-01'复制代码
还有一个建议,不要在列上进行运算,这也将致使索引失效而进行全表扫描。数据库
select * from news where id / 100 = 1复制代码
为了使用索引,防止执行全表扫描,能够进行改造。缓存
select * from news where id = 1 * 100复制代码
应该尽可能避免在 where 子句中使用 != 或 not in 或 <> 操做符,由于这几个操做符都会致使索引失效而进行全表扫描。微信
应该尽可能避免在 where 子句中使用 or 来链接条件,由于这会致使索引失效而进行全表扫描。数据库设计
select * from news where id = 1 or id = 2复制代码
MySQL 只能使用一个索引,会从多个索引中选择一个限制最为严格的索引,所以,为多个列建立单列索引,并不能提升 MySQL 的查询性能。函数
假设,有两个单列索引,分别为 news_year_idx(news_year) 和 news_month_idx(news_month)。如今,有一个场景须要针对资讯的年份和月份进行查询,那么,SQL 语句能够写成:性能
select * from news where news_year = 2017 and news_month = 1复制代码
事实上,MySQL 只能使用一个单列索引。为了提升性能,可使用复合索引 news_year_month_idx(news_year, news_month) 保证 news_year 和 news_month 两个列都被索引覆盖。
复合索引遵照“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。所以,在复合索引中索引列的顺序相当重要。若是不是按照索引的最左列开始查找,则没法使用索引。
假设,有一个场景只须要针对资讯的月份进行查询,那么,SQL 语句能够写成:
select * from news where news_month = 1复制代码
此时,没法使用 news_year_month_idx(news_year, news_month) 索引,由于遵照“最左前缀”原则,在查询条件中没有使用复合索引的第一个字段,索引是不会被使用的。
若是一个索引包含全部须要的查询的字段的值,直接根据索引的查询结果返回数据,而无需读表,可以极大的提升性能。所以,能够定义一个让索引包含的额外的列,即便这个列对于索引而言是无用的。
查询中的某个列有范围查询,则其右边全部列都没法使用索引优化查找。
举个例子,假设有一个场景须要查询本周发布的资讯文章,其中的条件是必须是启用状态,且发布时间在这周内。那么,SQL 语句能够写成:
select * from news where publish_time >= '2017-01-02' and publish_time <= '2017-01-08' and enable = 1复制代码
这种状况下,由于范围查询对多列查询的影响,将致使 news_publish_idx(publish_time, enable) 索引中 publish_time 右边全部列都没法使用索引优化查找。换句话说,news_publish_idx(publish_time, enable) 索引等价于 news_publish_idx(publish_time) 。
对于这种状况,个人建议:对于范围查询,务必要注意它带来的反作用,而且尽可能少用范围查询,能够经过曲线救国的方式知足业务场景。
例如,上面案例的需求是查询本周发布的资讯文章,所以能够建立一个news_weekth 字段用来存储资讯文章的周信息,使得范围查询变成普通的查询,SQL 能够改写成:
select * from news where news_weekth = 1 and enable = 1复制代码
然而,并非全部的范围查询均可以进行改造,对于必须使用范围查询但没法改造的状况,个人建议:没必要试图用 SQL 来解决全部问题,可使用其余数据存储技术控制时间轴,例如 Redis 的 SortedSet 有序集合保存时间,或者经过缓存方式缓存查询结果从而提升性能。
只要列中包含有 NULL 值都将不会被包含在索引中,复合索引中只要有一列含有 NULL值,那么这一列对于此复合索引就是无效的。
所以,在数据库设计时,除非有一个很特别的缘由使用 NULL 值,否则尽可能不要让字段的默认值为 NULL。
当查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换带来的影响就是可能致使索引失效而进行全表扫描。下面的案例中,date_str 是字符串,然而匹配的是整数类型,从而发生隐式转换。
select * from news where date_str = 201701复制代码
所以,要谨记隐式转换的危害,时刻注意经过同类型进行比较。
like 的方式进行查询,在 like "value%" 可使用索引,可是对于 like "%value%" 这样的方式,执行全表查询,这在数据量小的表,不存在性能问题,可是对于海量数据,全表扫描是很是可怕的事情。因此,根据业务需求,考虑使用 ElasticSearch 或 Solr 是个不错的方案。
(完)
更多精彩文章,尽在「服务端思惟」微信公众号!