MySQL手工指定表使用的索引


手动指定索引的语法:

USE {INDEX|KEY}
[{FOR {JOIN|ORDER BY|GROUP BY}} ([index_list])
| IGNORE {INDEX|KEY}
[{FOR {JOIN|ORDER BY|GROUP BY}} (index_list) |
FORCE {INDEX|KEY}

[{FOR {JOIN|ORDER BY|GROUP BY}} (index_list)

mysql强制索引和禁止某个索引

1、mysql强制使用索引:force index(索引名或者主键PRI)

select * from table force index(PRI) limit 2;(强制使用主键)

select * from table force index(ziduan1_index) limit 2;(强制使用索引"ziduan1_index")

select * from table force index(PRI,ziduan1_index) limit 2;(强制使用索引"PRI和ziduan1_index")


2、mysql禁止某个索引:ignore index(索引名或者主键PRI)

select * from table ignore index(PRI) limit 2;(禁止使用主键)
select * from table ignore index(ziduan1_index) limit 2;(禁止使用索引"ziduan1_index")
select * from table ignore index(PRI,ziduan1_index) limit 2;(禁止使用索引"PRI,ziduan1_index")


例如:
mysql> EXPLAIN SELECT artist_id, name, country_id
-> FROM artist WHERE founded = 1980 AND type='Band'\G
*********************  1. row ***********************
id: 1
select_type: SIMPLE
table: artist
type: ref
possible  _keys: founded,founded_2,type,type_2
key: founded
key_len: 2
ref: const
rows: 1216
Extra: Using where
1 row in set (0.01 sec)
在这个查询中优化器有多个索引可供选择,但它最终选择了
founded 索引。
下面的示例会提示优化器使用某个特定的索引:
 创建 MySQL 索引 
mysql> EXPLAIN SELECT artist_id, name, country_id
-> FROM artist USE INDEX (type)
-> WHERE founded = 1980 AND type='Band'\G
*********************  1. row ***********************
id: 1
select_type: SIMPLE
table: artist
type: refpossible_
keys: type
key: type
key_len: 1
ref: const
rows: 186720
Extra: Using where
可以看到在这个查询中使用了指定的索引。同样也可以要求优化器忽略某个索引:


mysql> EXPLAIN SELECT artist_id, name, country_id
-> FROM artist IGNORE INDEX (founded)
-> WHERE founded = 1980 AND type='Band'\G
*********************  1. row ***********************
id: 1
select_type: SIMPLE
table: artist
type: ref
possible_keys: founded_2,type,type_2
key: founded_2
key_len: 2
ref: const
rows: 1216
Extra: Using where
可以提供多个索引名或者多个索引提示:
mysql> EXPLAIN SELECT artist_id, name, country_id
-> FROM artist FORCE INDEX (founded,founded_2)   
Effective MySQL 之 SQL 语句最优化 92
->        USE INDEX (type_2)
-> WHERE founded = 1980 AND type='Band'\G
*********************  1. row ***********************
id: 1
select  _type: SIMPLE
table: artist
type: ref
possible_keys: type_2
key: type_2
key_len: 1
ref: const
rows: 177016
Extra: Using where


使用 MySQL 提示对更改全部的执行路径不会产生影响,因此你可以指定多个提示。使用 USE INDEX 提示会让 MySQL 从指定的索引中选择一个。FORCE INDEX 会对基于开销的优化器产生影响,让优化器更倾向于索引扫描而不是全表扫描。
提示
在 SQL 语句中添加提示是有很大风险的。尽管这可能会对查询有帮助,然而数据量随着时间的推移而变化会改变查询的有效性。添加或者改变表上的索引并不会影响到一个在特定索引中指定的硬编码 SQL 语句,所以查询提示应该是你最后考虑的方案




生产环境案例:
在公司后台某模块功能记录日志中有一个搜索功能,通过前段时间的产品使用时间区间进行搜索反馈有些卡顿,我发现这个搜索功能比较慢,要3秒左右才能出来,就决定对这里做一下优化。


通过分析代码和SQL发现最核心的问题在于一个区间查询耗时太长,耗时2秒多,所以我决定看看这里能不能优化,其中核心SQL为


SELECT  * FROM XXX_log WHERE (`ctime` BETWEEN '2017-09-11 09:34:13'  AND '2017-10-11 09:34:13')
and     id > 27851
AND column1 = 'xxx'
AND (column2 = 'null' OR LENGTH(column2) > 91)
ORDER BY  id DESC LIMIT 0, 30
这个查询是一个简单查询,没有联表,就是单表的limit分页查询,外加一个时间区间和字段搜索,我通过SQL分析 explain 发现并未走索引,扫描区间也很大,由于该表拥有接近100万的记录,查询的扫描区间接近50万,我感觉这样肯定是效率不高的。


然后查询了一下数据,发现耗时确实在2.6秒左右,我起初的设想是,column2字段查询肯定是没法改了 ,毕竟那涉及到以前的业务,该字段这样搜索查询确实有违常理,但是既然之前的功能已经这样设计了,现在去做调整,反而有可能有问题,那么就只有在 id ctime column1下手了,id它写死了,定了某条记录开始进行查询,我猜测可能之前的数据是测试数据或者是废弃数据,那既然有个标尺,就不去动它,column1是固定的查询值,这样也没法改,这样的固定值在数据行中差异不明显,加索引效果也不大,然后是ctime了,唯一能动文章的也只有它了。


然后我好好分析了一下这个模块要实现的功能逻辑,就是查询这段时间内符合要求的数据,这段时间,很明显是一个月,能不能设定这个查询区间只能查一个星期呢?


我改为一周内的时间区间查询,肯定能降低查询的查询区间啊,然而令人遗憾的是,这个降低查询区间间隔,并没有多大效果,最后无奈,我给ctime添加了一个 normal index btree索引,加了索引后,我本以为一切都会好起来,谁知,explain后效果还是那样!


可能用到的索引keys  主键 ctime  ,然而呢 查询区间还是接近45万,效果并不明显,查询时间也还是2秒多,这可让我犯难了,一时束手无策,思考许久,突然想到这感觉是索引没有真正生效导致的,那么能不能强制告诉mysql使用某个索引了,让他主动是走某个索引,然后我查询了资料 找到了force index(强制要走的那个索引) ,我马上就试了一下


SELECT  * FROM XXX_log force index(ctime) WHERE (`ctime` BETWEEN '2017-09-11 09:34:13'  AND '2017-10-11 09:34:13')
and     id > 27851
AND column1 = 'xxx'
AND (column2 = 'null' OR LENGTH(column2) > 91)
ORDER BY  id DESC LIMIT 0, 30
果然 explain分析之后 使用了ctime索引


而且查询区间降低到3万多了,这个效果太明显了,耗时降低到0.2秒左右,然后这个功能马上从3秒才能打开降低到0.3秒就能打开了,这个优化效果令我非常满意。


 
分割线
感谢打赏
江西数库信息技术有限公司
YWSOS.COM 平台代运维解决方案
 评论
 发表评论
姓   名:

Powered by AKCMS