”种一棵树最好是十年前,其次是现在“,结合个人十多年IT基础架构领域摸爬滚打的经验来看,数据库领域潜力无限,大有可为。运维领域知识面需要广,更需要专,数据库是我选择做专做深的方向。
今天继续来跟大家聊一聊关于索引的性能分析,使用规则,设计原则方面的知识,至此索引方面的知识就分享完毕了
索引知识概览
性能分析工具
- 执行频次查看
#查看增,删,改,查执行频次:
#查看全局
show global status like “Com_______”;
#查看当前session
show session status like “Com_______”;
- 慢查询日志
默认执行时间超过10s的增删改查语句,都会被记录到日志中,默认不开启,需要在/etc/my.cnf配置文件中开启
#开启慢查询日志开关
slow_query_log=1
#设置慢查询日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志中
long_query_time=2
需要重启mysql使配置生效,日志位置:/var/lib/mysql/{hostname}-slow.log
查询慢查询是否开启:show variables like “slow_query_log”
- profile详情
#版本是否支持
select @@have_profiling;
#profile是否开启
select @@profiling;
#开启profile
set profiling = 1;
#查看所有语句的耗时
show profiles;
#查看指定sql语句的详细耗时
show profiles for query query_id;
#查看指定sql语句的cpu开销
show profiles cpu for query query_id;
- explain
一条SQL语句除了要知道它整体运行耗时之外,我们还需要了解它内部的运行详细细节,这时就需要请出explain这个工具登场了。
explain的作用:能够把一条大SQL语句详细拆解成一条条子语句,然后展示每条子语句的执行优先顺序,以及连接类型等信息
语法:
直接在select语句前加上explain或desc
查询结果各字段含义:
id:查询结果子句的序号,id越大越先执行,id相同顺序执行
select_type:查询类型,常见的有simple,primary,union,subquery
type:查询类型, 性能由好到差依次为:NULL(不查任何表)、system(查询系统表)、const(主键或唯一索引)、eq_ref、ref(非唯一索引)、range、index(遍历整个索引树)、all(全表扫描)
possible_key:可能用到的索引
key:实际用到的索引
key_len:索引长度
rows:返回的行数
filtered:返回的行数占查询行数的百分比,值越大越好
extra:额外信息
红线红框部分需要重点关注
使用规则
- 最左前缀法则
多列都属于同一个索引名称情况下,遵循最左前缀法则。查询从最左列开始,不能跳过索引中的列(只要最左列存在即可)。
如果跳过最左列,则索引失效,如果跳过中间列,则后面的列索引失效。
验证例子(使用explain):
范围查询右侧的列索引失效(第二条是解决方案)
- 索引失效情况
在索引列上进行运算操作,索引将失效。
例如:explain select * from tb_user where substring(phone, 10, 2) = '15';
字符串类型使用时不加引号,索引将失效。
例如:explain select * from tb_user where phone = 17799990015;
模糊查询中,仅仅匹配尾部,索引不会失效。但是匹配头部,索引则会失效。
例如:explain select * from tb_user where profession like '%工程';
用or分割开的条件,其中有一列没用索引,那么整体索引都不会用到
查询表中的数据量,MYSQL评估全表扫描比索引快,则放弃使用索引
- SQL提示
sql提示是非常重要的一种优化手段,可以人为的指定/忽略使用哪个索引。
例如,建议使用索引(最终由mysql决定):
explain select * from tb_user use index(idx_user_pro) where profession="软件工程";
不使用指定索引:
explain select * from tb_user ignore index(idx_user_pro) where profession="软件工程";
强制使用指定索引:
explain select * from tb_user force index(idx_user_pro) where profession="软件工程";
- 覆盖索引&回表查询
尽量使用覆盖索引(查询使用到了索引,并且查询返回的列都在索引中能找到),如下图:
在辅助索引中无法查到时,需要到聚集索引中查,这就是回表查询(性能比覆盖索引差,查询了两次),如下图:
面试题:
一张表,有四个字段(id, username, password, status),由于数据量大,需要对以下SQL语句进行优化,该如何进行才是最优方案:
select id, username, password from tb_user where username='itcast';
解:给username和password字段建立联合索引,则不需要回表查询,直接覆盖索引
- 前缀索引
碰到类似text类型的字段,需要建立索引的情况。由于该类型字段占用空间太大,不能直接整个建立索引,需要截取固定长度的前缀做索引。从而节约索引空间,提高索引效率。
这里有一个问题:如何确定前缀截取长度呢?可以通过不重复记录数和总体记录数的比值来确定,数值越高,查询准确率越高。 例如: select count(distinct email) / count(*) from tb_user;
有些场景需要考虑截取长度,则需要降低选择性数值 列如: 这种场景截取长度选择5则是最优解
- 单列索引&联合索引
顾名思义单列索引是只对一列建立索引,联合索引则是对多列建立索引。
使用场景:大部分查询语句都需要查询多列数据,为了提高查询效率,减少回表查询次数,则需要使用联合索引,并手动指定使用自己创建的联合索引
如下:默认mysql不会使用用户创建的联合索引,需要手动指定
索引设计原则
1.对于数据量较大(100万条以上),且查询比较频繁的表需要建立索引
2.常作为查询条件(where),排序(order by),分组(group by)的字段建立索引
3.选择区分度高的列建立索引,尽量使用唯一索引。区分度越高,索引效率越高
4.如果是字符串或者文本类型的字段,可以根据字符串的特点,建立前缀索引
5.尽量使用联合索引,避免单列索引。可以节省存储空间,避免回表查询,提高查询效率
6.要控制索引的数量,索引越多维护索引结构的代价就越大,会影响增删改的效率
7.如果索引列不能存储NULL值,需要在建表时使用NOT NULL约束,便于优化器知道用户哪个索引最有效
作者:谷会于(转载请获本人授权,并注明作者与出处)
本文使用 文章同步助手 同步