MYSQL之慢查询与索引

慢查询为查询时间超过指定值,mysql中语句执行超过设定值long_query_time,即被记录到慢查询日志中去,一般作为查询的优化手段,建立索引是一个比较不错的选择,那么我们可以说我们建立好索引后,sql用到了此索引,就可以解决慢查询问题了吗?

其实,mysql慢查询与索引其实没有必然的联系,因为查询的过滤性与索引的过滤性不同。我们以下面为例子。

现在我们有一个用户列表,表结构如下:

名称类型长度
idbigint0
namevarchar10
phonevarchar20
age

int

0
adreessvarchar50

 

 

 

 

 

 

字段name与age建立联合索引index_name|_age(name,age);

假设我们现在要查询表中符合name为张三,年龄为20的数据,我们的sql为:

select t.* from t_test t where t.name ='张三' and t.age=20 

这时候我们发现查询的语句很快,原因如下:

1.符合条件的语句很少;

2.索引的过滤性足够好,根据最左匹配原则,name与age是查询全等数据,且Btree的查询规则为顺序查询,那么在维护的联合索引树上只要从用第一个符合name为张三,age为20,顺序查找到name不为张三,或者age不为20的数据即可,

以我的模拟数据为例子,表中的模拟数据如下:

 

idnamephoneageadreess
1张三1310000000020北京市
2张三1310000000020天津市
3张三1310000000021武汉市
4张四1310000000020石家庄市

 

 

 

 下面我们看下sql执行计划,语句为:

explain select t.* from t_test t where t.name ='张三' and t.age=20 

执行结果如下:

dselect_typetablepartitionstypepossible_keyskeykey_lengthrefrowsfilteredExtra
1SIMPLEt refiindex_name_ageindex_name_age38const2100 

 

 

根据rows可以看出,我们只查询了符合条件的2行数据。

那么下面我们有了一个新的要求,要查询出符合name第一个名字为张的,年龄为20的数据,那么我们该怎么办呢,我们可能会这样编写sql:

select t.* from t_test t where t.name like '张%' and t.age=20 

查询结果是我们想要的,并且查看下执行计划:

dselect_typetablepartitionstypepossible_keyskeykey_lengthrefrowsfilteredExtra
1SIMPLEt rangeiindex_name_ageindex_name_age38 4100Using index condition

 

 

我们用到了我们建立的联合索引,这时我们可能以为达到要求了,但是rows中的4,数据扫描了表中的所有数据,即为四行,同时,Extra中Using index condition 为通过联合索引优化了你的回表次数,那么我们可以减少表的扫描行数吗,答案是肯定的。我们使用5.7版本后引入的虚拟列,具体语法如下:

ALTER TABLE t_test ADD name_first VARCHAR (2) generated always AS (LEFT(NAME, 1)),ADD INDEX (name_first, age);

这时我们看表中就多了一个名为name_first的列,并且多了一个名字为name_first的索引,此时的name_first列不可更改与指定,是随着我们name字段自动生成的,这时我们重新编写sql语句:

select t.* from t_test t where t.name_first ='张' and age =20

我们看下执行计划,语句省略,执行计划如下:

dselect_typetablepartitionstypepossible_keyskeykey_lengthrefrowsfilteredExtra
1SIMPLEt refname_firstname_first14const,const3100 

 

 

 

可以看到,根据最左匹配原则,过滤器只需要查找符合规定的数据即可,同样省去了优化器帮助我们减少回表次数。

这时由于之前的索引树中,数据存储的顺序是这样的(树形状省略):(张三,20),(张三,20),(张三,21),(张四,20),这样一来顺序匹配的要经过(张三,21),所以为四行。

我们加入虚拟列之后的联合索引存储数据为(树形状省略):(张,20),(张,20),(张,20),(张,21),这样我们只要根据顺序匹配前三个即可,然后根据取出的主键id,进行回表数据查找。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值