索引失效(存在索引但不使用索引)

Posted 学无止境

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了索引失效(存在索引但不使用索引)相关的知识,希望对你有一定的参考价值。

存在索引但不使用索引
(1)如果mysql估计使用索引比全表扫描更慢,则不使用索引。例如如果列key_part1均匀分布在1到100之间,查询时使用索引就不是很好

mysql>select * from table_name where key_part1>1 and key_part<90;

(2)如果使用MEMORY/HEAP表并且where条件中不使用“=”进行索引列,那么不会用到索引。Heap表只有在“=”的条件下会使用索引

(3)用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到

mysql>show index from sales\G 
*************************** 1. row *************************** 
…… 
key_name: ind_sales_year 
seq_in_index:1 
Column_name: year 
……

从上面可以发现只有year列上面有索引。来看如下的执行计划。

mysql> explain select * from sales where year=2001 or country=‘China\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: sales 
type: ALL 
possible_keys: ind_sales_year 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 12 
Extra: Using where 
1 row in set (0.00 sec)

(4)如果将要使用的索引列不是复合索引列表中的第一部分,则不会使用索引

如下例子:可见虽然在money上面建有复合索引,但是由于money不是索引的第一列,那么在查询中这个索引也不会被MySQL采用。

mysql> explain select * from sales2 where moneys=1 \G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: sales2 
type: ALL 
possible_keys: NULL 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 1000 
Extra: Using where 
1 row in set (0.00 sec)

(5)如果like是以%开始,可见虽然在name上面建有索引,但是由于where 条件中like的值的“%”在第一位了,那么MySQL也会采用这个索引。

(6)对列变量需要计算(聚合运算、类型转换等)

如果列类型是字符串,但在查询时把一个数值型常量赋值给了一个字符型的列名name,那么虽然在name列上有索引,但是也没有用到。

mysql> explain select * from company2 where name name=294\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: company2 
type: ALL 
possible_keys: ind_company2_name 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 1000 
Extra: Using where 
1 row in set (0.00 sec)

而下面的sql语句就可以正确使用索引。

mysql> explain select * from company2 where name name=‘294‘\G 
*************************** 1. row *************************** 
id: 1 
select_type: SIMPLE 
table: company2 
type: ref 
possible_keys: ind_company2_name 
key: ind_company2_name 
key_len: 23 
ref: const 
rows: 1 
Extra: Using where 
1 row in set (0.00 sec)

查看索引使用情况
如果索引正在工作,Handler_read_key的值将很高,这个值代表了一个行被索引值读的次数。

Handler_read_rnd_next的值高则意味着查询运行低效,并且应该建立索引补救。

mysql> show status like ‘Handler_read%‘; 
+-----------------------+-------+ 
| Variable_name | Value | 
+-----------------------+-------+ 
| Handler_read_first | 0 | 
| Handler_read_key | 5 | 
| Handler_read_next | 0 | 
| Handler_read_prev | 0 | 
| Handler_read_rnd | 0 | 
| Handler_read_rnd_next | 2055 | 
+-----------------------+-------+ 
6 rows in set (0.00 sec)

两个简单实用的优化方法

分析表的语法如下:(检查一个或多个表是否有错误)

mysql> CHECK TABLE tbl_name[,tbl_name] …[option] …option = 
{ QUICK | FAST | MEDIUM| EXTENDED | CHANGED} 
mysql> check table sales; 
+--------------+-------+----------+----------+ 
| Table | Op | Msg_type | Msg_text | 
+--------------+-------+----------+----------+ 
| sakila.sales | check | status | OK | 
+--------------+-------+----------+----------+ 
1 row in set (0.01 sec)

优化表的语法格式:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,tbl_name]
如果已经删除了表的一大部分,或者如果已经对含有可变长度行的表进行了很多的改动,则需要做定期优化。这个命令可以将表中的空间碎片进行合并,但是此命令只对MyISAM、BDB和InnoDB表起作用。

mysql> optimize table sales; 
+--------------+----------+----------+----------+ 
| Table | Op | Msg_type | Msg_text | 
+--------------+----------+----------+----------+ 
| sakila.sales | optimize | status | OK | 
+--------------+----------+----------+----------+ 
1 row in set (0.05 sec)

以上是关于索引失效(存在索引但不使用索引)的主要内容,如果未能解决你的问题,请参考以下文章

MySQL联合索引生效的条件、索引失效的条件

java.lang.IllegalStateException:键 f0 的片段不再存在:索引 1

如何查看oracle失效的索引

失效主键唯一索引还存在的一种解决方法

mysql 索引失效总结

Oracle 索引失效