zoukankan      html  css  js  c++  java
  • 索引-mysql

    索引使用的注意事项(策略及优化)

    并不是建立索引就能显著提高查询速度,在索引的使用过程中,存在一些使用细节和注意事项,因为稍不留心,就可能导致在查询过程中索引失效。

    一下列举一些需要注意的事项:

    1. 不要在列上使用函数

    不要在列上使用函数,这将导致索引失效而进行全表扫描。

    如:

    1
    select * from news where year(publish_time) < 2018

    应改为:

    1
    select * from news where publish_time < '2018-01-01'

    2. 不要在列上进行计算

    不要在列上进行运算,这也将导致索引失效而进行全表扫描。

    如:

    1
    select * from news where id / 100 = 1

    应改为:

    1
    select * from news where id = 1 * 100

    3. 尽量避免使用 != 或 not in或 <> 等否定操作符

    应该尽量避免在 where 子句中使用 != 或 not in 或 <>操作符,
    这些负向查询也会导致索引失效而进行全表扫描。

    如:

    1
    select name from user where id not in (1,3,4);

    应改为:

    1
    select name from user where id in (2,5,6);

    4. 尽量避免使用 or 来连接条件

    应该尽量避免在 where 子句中使用 or来连接条件,因为这会导致索引失效而进行全表扫描。

    如:

    1
    select * from CRM_CUSTOMER_INFO where id= 1 or id =2

    应改为

    1
    select * from CRM_CUSTOMER_INFO where id in(1,2)

    5. 字段的默认值不要为 null

    只要列中包含有 NULL 值都将不会被包含在索引中,复合索引中只要有一列含有 NULL值,那么这一列对于此复合索引就是无效的。

    因此,在数据库设计时,除非有一个很特别的原因使用 NULL 值,不然尽量不要让字段的默认值为 NULL。

    6. 不要让数据库帮我们做隐式类型转换

    当查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换带来的影响就是可能导致索引失效而进行全表扫描。

    1
    select name from user where telno=1888888888

    这样虽然可以查出数据,但是会导致全表扫描。

    应改为

    1
    select name from user where telno='1888888888'

    7. 前导模糊查询会导致索引失效

    like 的方式进行查询,在 like “value%” 可以使用索引,但是对于 like “%value%” 这样的方式,执行全表查询,这在数据量小的表,不存在性能问题,但是对于海量数据,全表扫描是非常可怕的事情。所以,根据业务需求,考虑使用 ElasticSearch 或 Solr 是个不错的方案。

    8. 数据区分不明显的不建议创建索引

    如 user 表中的性别字段,可以明显区分的才建议创建索引,如身份证等字段

    9. 可以用复合索引替代多个单列索引

    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 两个列都被索引覆盖。

    10. 覆盖索引的好处

    如果一个索引包含所有需要的查询的字段的值,直接根据索引的查询结果返回数据,而无需读表,能够极大的提高性能。因此,可以定义一个让索引包含的额外的列,即使这个列对于索引而言是无用的。

    11. 范围查询对多列查询的影响

    查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。

    举个例子,假设有一个场景需要查询本周发布的资讯文章,其中的条件是必须是启用状态,且发布时间在这周内。那么,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 可以改写成:

    1
    select * from news where news_weekth = 1 and enable = 1

    然而,并不是所有的范围查询都可以进行改造,对于必须使用范围查询但无法改造的情况,我的建议:不必试图用 SQL 来解决所有问题,可以使用其他数据存储技术控制时间轴,例如 Redis 的 SortedSet 有序集合保存时间,或者通过缓存方式缓存查询结果从而提高性能。

    12. 复合索引(联合索引)

    首先介绍一下联合索引。联合索引其实很简单,相对于一般索引只有一个字段,联合索引可以为多个字段创建一个索引。它的原理也很简单,比如,我们在(a,b,c)字段上创建一个联合索引,则索引记录会首先按照A字段排序,然后再按照B字段排序然后再是C字段,因此,联合索引的特点就是:

    第一个字段一定是有序的
    当第一个字段值相等的时候,第二个字段又是有序的,比如下表中当A=2时所有B的值是有序排列的,依次类推,当同一个B值得所有C字段是有序排列的

    ABC
    1 2 3
    1 4 2
    1 1 4
    2 3 5
    2 4 4
    2 4 6
    2 5 5

    其实联合索引的查找就跟查字典是一样的,先根据第一个字母查,然后再根据第二个字母查,或者只根据第一个字母查,但是不能跳过第一个字母从第二个字母开始查。这就是所谓的最左前缀原理。

    13. 复合索引的最左前缀原理

    在复合索引的基础上,再来详细介绍一下联合索引的查询。还是复合索引中的例子,我们在(a,b,c)字段上建了一个联合索引,所以这个索引是先按a 再按b 再按c进行排列的,所以:

    以下的查询方式都可以用到索引

    select * from table where a=1;
    select * from table where a=1 and b=2;
    select * from table where a=1 and b=2 and c=3;

    上面三个查询按照 (a ), (a,b ),(a,b,c )的顺序都可以利用到索引,这就是最左前缀匹配。

    如果查询语句是:

    select * from table where a=1 and c=3; 那么只会用到索引a。

    如果查询语句是:

    select * from table where b=2 and c=3; 因为没有用到最左前缀a,所以这个查询是用户到索引的。

    如果用到了最左前缀,但是顺序颠倒会用到索引吗?

    比如:

    select * from table where b=2 and a=1;
    select * from table where b=2 and a=1 and c=3;

    如果用到了最左前缀而只是颠倒了顺序,也是可以用到索引的,因为mysql查询优化器会判断纠正这条sql语句该以什么样的顺序执行效率最高,最后才生成真正的执行计划。但我们还是最好按照索引顺序来查询,这样查询优化器就不用重新编译了。

  • 相关阅读:
    Redis常见问题及解决方案
    Maven构建报错问题解决
    Nginx正向代理设置
    Linux下限制某程序CPU占用
    Linux-flock文件锁的使用
    Python将print输出内容保存到指定文件中
    使用Zabbix官方模板监控Redis运行状况
    阿里云ossfs配置
    docker swarm 集群及可视化界面的安装及配置
    http://www.fx114.net/qa-24-116329.aspx
  • 原文地址:https://www.cnblogs.com/htq29study/p/12002583.html
Copyright © 2011-2022 走看看