MySQL设置索引的原则和技巧

目录

一、查看索引使用情况

二、 索引的使用技巧


一、查看索引使用情况

mysql> show status like 'handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 0     |
| Handler_read_last     | 0     |
| Handler_read_next     | 0     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 16    |
+-----------------------+-------+

Handler_read_key        #这个值越高越好,越高表示使用索引查询到的次数
Handler_read_rnd_next   #这个值越高,说明查询低效

二、 索引的使用技巧

1、搜索的索引列,不一定是所要选择的列。

        换句话说,最适合索引的列是出现在 WHERE 子句中的列,或连接子句中指定的列,而不是出现在 SELECT 关键字后的选择列表中的列。

select user_id from user;

#不是因为要搜索user_id而加索引,而是为了后面的where 条件加索引,不会出现在where 子句中的字段不该创建索引

2、使用唯一索引。

考虑某列中值的分布。对于惟一值的列,索引的效果最好,而具有多个重复值的列,其索引效果最差。

例如,存放年龄的列具有不同值,很容易区分 各行。 而用来记录性别的列,只含有“ M” 和“F” ,则对此列进行索引没有多大用处(不管 搜索哪个值,都会得出大约一半的行)

列值唯一性太差的不适合单独创建索引

3、较频繁的作为查询字段应该创建索引

4、使用短索引。

如果对字符串列进行索引,应该指定一个前缀长度,只要有可能就应该这样做。

例如,如果有一个 CHAR(200) 列,如果在前 10 个或 20 个字符内,多数值是惟一的, 那么就不要对整个列进行索引。对前 10 个或 20 个字符进行索引能够节省大量索引空 间,也可能会使查询更快。较小的索引涉及的磁盘 I/O 较少,较短的值比较起来更快。

更为重要的是,对于较短的键值,索引高速缓存中的块能容纳更多的键值,因此, MySQL也可以在内存中容纳更多的值。这增加了找到行而不用读取索引中较多块的可能性。

(当然,应该利用一些常识。如仅用列值的第一个字符进行索引是不可能有多大好处的, 因为这个索引中不会有许多不 同的值。)

5、利用最左前缀。

在创建一个 n 列的索引时,实际是创建了 MySQL 可利用的 n 个索引。

多列索引可起几个索引的作用,因为可利用索引中最左边的列集来匹配行。这样的列集称为最左前缀。(这与索引一个列的前缀不同,索引一个列的前缀是利用该列的前 n 个字符作为索引值。)

6、不要过度索引。

不要以为索引“越多越好” ,什么东西都用索引是错的。

每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能, 修改表的内容时,索引必须进行更新,有时可能需要重构,因此,索引越多,所花的时间越长。如果有一个索引很少利用或从不使用,那么会不必要地减缓表的修改速度。

此外, MySQL 在生成一个执行计划时,要考虑各个索引,这也要费时间。创建多余的索引给查询优化带来了更多的工作。索引太多,也可能会使 MySQL 选择不到所要使用的最好索引。只保持所需的索引有利于查询优化。

如果想给已有索引的表增加索引,应该考虑所要增加的索引是否是现有多列索引的最左索引。如果是,则就不要费力去增加这个索引了,因为已经有了。

频繁更新的字段不适合创建索引频繁更新的字段不适合创建索引

7、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

Null值不存储在索引中,因此在索引列上带is null 条件的查询不会使用索引

mysql> explain select * from user where uname is null;
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+

同样is not null 也不走索引

可以修改成:

select id from t where num=0 

8、考虑在列上进行的比较类型。

索引可用于“ <” 、 “ <= ” 、 “ = ” 、 “ >=” 、 “ > ” 和 BETWEEN 运算。

应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。

mysql> explain select * from user where uname != 'haha';
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | user  | ALL  | uname         | NULL | NULL    | NULL | 10000000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from user where uname > 'haha';
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | range | uname         | uname | 63      | NULL |    4 | Using where |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+

#in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据
select id from t where num in(1,2,3)

#对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

9、like 使用非打头字母搜索。

这也使得引擎无法利用索引。'%hello'用不上,'hello%' 用的上

mysql> explain select * from user where uname like '%haha';
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL | 10000000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from user where uname like 'aha%';
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
|  1 | SIMPLE      | user  | range | uname         | uname | 63      | NULL |    1 | Using where |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+

10、应尽量避免在 where 子句中使用 or 来连接条件,否则可能将导致引擎放弃使用索引而进行全表扫描,如:

mysql> explain select * from t1 where cat_id = 8 or cat_id = 3;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | ALL  | cat_id        | NULL | NULL    | NULL |   31 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


mysql> explain select * from t1 where cat_id = 3;
+----+-------------+-------+------+---------------+--------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | rows | Extra |
+----+-------------+-------+------+---------------+--------+---------+-------+------+-------+
|  1 | SIMPLE      | t1    | ref  | cat_id        | cat_id | 2       | const |   14 |       |
+----+-------------+-------+------+---------------+--------+---------+-------+------+-------+

11、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描

mysql> explain select * from t1 where cat_id +1 = 3;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |   31 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

12、应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描

13、如果列类型是字符串,那一定要在条件中将数据使用引号 引用起来,否则不使用索引

 

mysql> explain select * from user where uname = '111';
+----+-------------+-------+------+---------------+-------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-------------+
|  1 | SIMPLE      | user  | ref  | uname         | uname | 63      | const |    1 | Using where |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from user where uname = 111;
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | user  | ALL  | uname         | NULL | NULL    | NULL | 10000000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+----------+-------------+

14、如果mysql估计使用全表扫描要比使用索引快,则不使用索引

当一条Query返回的数据超过了全表的 15%时,就不应该再使用索引扫描来完成这个 Query 了。对于"15%"这个数字我们并不能判定是否很准确,但是至少侧面证明了唯一性太差的字段并不适合创建索引。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值