mysql索引的新手入门

前言

如果是小白的话,我觉得看到这篇文章一定会对博主赞赏有加,因为实在是太好了,没错,博主就是要让你喜欢上。

1、索引

索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据。对于索引,会保存在额外的文件中。
2、索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置,然后直接获取即可。

1.1、索引选取类型

1、越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。

2、简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。

3、尽量避免NULL:应该指定列为NOT nuLL,在MySQL中, 含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂

1.2、什么场景不适合创建索引

第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因 为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那 些只有很少数据值的列也不应该增加索引。因为本来结果集合就是相当于全表查询了,所以没有必要。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比 例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索 引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因 此,当修改性能远远大于检索性能时,不应该创建索引。
第五,不会出现在where条件中的字段不该建立索引。
1.3、什么样的字段适合创建索引

1、表的主键、外键必须有索引;
2、数据量超过300的表应该有索引;
3、经常与其他表进行连接的表,在连接字段上应该建立索引;
4、经常出现在Where子句中的字段,加快判断速度,特别是大表的字段,应该建立索引,建立索引,一般用在select ……where f1 and f2 ,我们在f1或者f2上建立索引是没用的。只有两个都有索引才能有用
5、经常用到排序的列上,因为索引已经排序。
6、经常用在范围内搜索的列上创建索引,因为索引已经排序了,其指定的范围是连续的
7、经常用到搜索的列上,可以加快搜索的速度

2、索引优缺点

2.1、优点

索引由数据库中一列或多列组合而成,其作用是提高对表中数据的查询速度
索引的优点是可以提高检索数据的速度

2.2、缺点

索引的缺点是创建和维护索引需要耗费时间
索引可以提高查询速度,会减慢写入速度

3、索引分类

1,普通索引:

仅加速查询 最基本的索引,没有任何限制,是我们大多数情况下使用到的索引。

2,唯一索引:

与普通索引类型,不同的是:加速查询 + 列值唯一(可以有null)

3,全文索引:

全文索引(FULLTEXT)仅可以适用于MyISAM引擎的数据表;作用于CHAR、VARCHAR、TEXT数据类型的列。

4,组合索引:

在这里要指出,组合索引和前缀索引是对建立索引技巧的一种称呼,并不是索引的类型。为了更好的表述清楚,建立一个demo表如下。
create table USER_DEMO
(
ID int not null auto_increment comment ‘主键’,
LOGIN_NAME varchar(100) not null comment ‘登录名’,
PASSWORD varchar(100) not null comment ‘密码’,
CITY varchar(30) not null comment ‘城市’,
AGE int not null comment ‘年龄’,
SEX int not null comment ‘性别(0:女 1:男)’,
primary key (ID)
);
 为了进一步榨取mysql的效率,就可以考虑建立组合索引,即将LOGIN_NAME,CITY,AGE建到一个索引里:
 ALTER TABLE USER_DEMO ADD INDEX name_city_age (LOGIN_NAME(16),CITY,AGE);

建表时,LOGIN_NAME长度为100,这里用16,是因为一般情况下名字的长度不会超过16,这样会加快索引查询速度,还会减少索引文件的大小,提高INSERT,UPDATE的更新速度。

如果分别给LOGIN_NAME,CITY,AGE建立单列索引,让该表有3个单列索引,查询时和组合索引的效率是大不一样的,甚至远远低于我们的组合索引。虽然此时有三个索引,但mysql只能用到其中的那个它认为似乎是最有效率的单列索引,另外两个是用不到的,也就是说还是一个全表扫描的过程。

建立这样的组合索引,就相当于分别建立如下三种组合索引:
LOGIN_NAME,CITY,AGE
LOGIN_NAME,CITY
LOGIN_NAME
 为什么没有CITY,AGE等这样的组合索引呢?这是因为mysql组合索引“最左前缀”的结果。简单的理解就是只从最左边的开始组合,并不是只要包含这三列的查询都会用到该组合索引。也就是说name_city_age(LOGIN_NAME(16),CITY,AGE)从左到右进行索引,如果没有左前索引,mysql不会执行索引查询。

如果索引列长度过长,这种列索引时将会产生很大的索引文件,不便于操作,可以使用前缀索引方式进行索引,前缀索引应该控制在一个合适的点,控制在0.31黄金值即可(大于这个值就可以创建)。

SELECT COUNT(DISTINCT(LEFT(title,10)))/COUNT(*) FROM Arctic; – 这个值大于0.31就可以创建前缀索引,Distinct去重复

ALTER TABLE user ADD INDEX uname(title(10)); – 增加前缀索引SQL,将人名的索引建立在10,这样可以减少索引文件大小,加快索引查询速度

1、普通索引

1.1.1、创建表的时候同事创建索引

create table healerjean (
id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT ‘主键’,
name VARCHAR(32) NOT NULL COMMENT ‘姓名’,
email VARCHAR(64) NOT NULL COMMENT ‘邮箱’,
message text DEFAULT NULL COMMENT ‘个人信息’,
INDEX index_name (name) COMMENT ‘索引name’
) COMMENT = ‘索引测试表’;

1.1.2、在存在的表上创建索引

create index index_name on healerjean(name)

1.1.3、注意:

对于创建索引时如果是blob 和 text 类型,必须指定length。

create index ix_extra on in1(message(200));

1.2、删除索引
drop index_name on healerjean;

1.3、查看索引

这个时候,我们会发现其实主键id也是一个索引

show index from healerjean;

2、主键索引 (我们一般都会提供主键的,默认主键就是索引)

3、正确使用索引

文章相当出色,请查看。主要是看explain 中出现的row有有多少行,行数越多,表示执行速度越慢

https://www.cnblogs.com/Cheney222/articles/5876382.html

如果以错误的方式使用,则即使建立索引也会不奏效。

3.1、对于创建的多列索引,只要查询的条件中用到了最左边的列,索引一般就会被使用

1、首先按 company_id,moneys 的顺序创建一个复合索引,具体如下:

mysql> create index ind_sales2_companyid_moneys on sales2(company_id,moneys);
Query OK, 1000 rows affected (0.03 sec)
Records: 1000 Duplicates: 0 Warnings: 0

2、然后按 company_id 进行表查询,具体如下:

mysql> explain select * from sales2 where company_id = 2006\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: sales2
type: ref
possible_keys: ind_sales2_companyid_moneys
208key: ind_sales2_companyid_moneys
key_len: 5
ref: const
rows: 1
Extra: Using where
1 row in set (0.00 sec)

3、可以发现即便 where 条件中不是用的 company_id 与 moneys 的组合条件,索引仍然能用到,这就是索引的前缀特性。

4、但是如果只按 moneys 条件查询表,那么索引就不会被用到,具体如下:

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)

3.2、对于使用 like 的查询,后面如果是常量并且只有%号不在第一个字符,索引才可能会被使用:

1、 可以发现第一个例子没有使用索引,而第二例子就能够使用索引,
2、 区别就在于“%”的位置不同,前者把“%”放到第一位就不能用到索引,而后者没有放到第一位就使用了索引。

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

mysql> explain select * from company2 where name like ‘3%’\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: company2
type: range
209possible_keys: ind_company2_name
key: ind_company2_name
key_len: 11
ref: NULL
rows: 103
Extra: Using where
1 row in set (0.00 sec)

3.3、如果列名是索引,使用 column_name is null 将使用索引。

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

3.4、如果对大的文本进行搜索,使用全文索引而不用使用 like ‘%…%’。

4、存在索引,但是不使用

4.1、如果 MySQL 估计使用索引比全表扫描更慢,则不使用索引。例如,如果列key_part1 均匀分布在 1 和 100 之间,下列查询中使用索引就不是很好:

SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90;

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

4.3、用 or 分割开的条件,如果 or 前的条件中的列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到,例如:,必须or前后都有索引才能被使用

mysql> show index from sales\G;
*************************** 1. row ***************************
Table: sales
Non_unique: 1
Key_name: ind_sales_year
Seq_in_index: 1
Column_name: year
210Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
1 row in set (0.00 sec)

4.4、如果列是字符型,,传入的是数字,则不上‘’不会使用索引

mysql> explain select * from company2 where 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)

mysql> explain select * from company2 where 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)

5、执行计划

explain + 查询SQL – 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

1、id,查询顺序标识

2、select_type,查询类型

SIMPLE 简单查询
PRIMARY 最外层查询
SUBQUERY 映射为子查询
DERIVED 子查询
UNION 联合
UNION RESULT 使用联合的结果

3、type 查询时的访问方式

性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const

1、ALL、全表扫描,对于数据表从头到尾找一遍 select * from tb1;特别的:如果有limit限制,则找到之后就不在继续向下扫描
虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。

mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE location = '2222' ;

±—±------------±---------------±-----------±-----±--------------±-----±--------±-----±-----±---------±------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±---------------±-----------±-----±--------------±-----±--------±-----±-----±---------±------------+
| 1 | SIMPLE | t_mobilesms_11 | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where |
±—±------------±---------------±-----------±-----±--------------±-----±--------±-----±-----±---------±------------+
1 rows in set (0.02 sec)

2、INDEX 、全索引扫描,对索引从头到尾找一遍
select nid from tb1;

3、RANGE 、对索引列进行范围查找
PS:
between and
in
> >= < <= 操作
注意:!= 和 > 符号

mysql> EXPLAIN SELECT * FROM `t_mobilesms_11` WHERE userid < '2222' ;

±—±------------±---------------±-----------±------±--------------±-------------±--------±-----±-----±---------±----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±---------------±-----------±------±--------------±-------------±--------±-----±-----±---------±----------------------+
| 1 | SIMPLE | t_mobilesms_11 | NULL | range | 联合索引 | 联合索引 | 767 | NULL | 1 | 100.00 | Using index condition |
±—±------------±---------------±-----------±------±--------------±-------------±--------±-----±-----±---------±----------------------+
1 rows in set (0.03 sec)

4、INDEX_MERGE、合并索引,使用多个单列索引搜索
select * from tb1 where name = ‘alex’ or nid in (11,22,33);

5、REF、根据索引查找一个或多个值

mysql> EXPLAIN SELECT * FROM t_mobilesms_11 WHERE userid = ‘2222’ ;
±—±------------±---------------±-----------±-----±--------------±-------------±--------±------±-----±---------±------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
±—±------------±---------------±-----------±-----±--------------±-------------±--------±------±-----±---------±------+
| 1 | SIMPLE | t_mobilesms_11 | NULL | ref | 联合索引 | 联合索引 | 767 | const | 1 | 100.00 | NULL |
±—±------------±---------------±-----------±-----±--------------±-------------±--------±------±-----±---------±------+
1 rows in set (0.04 sec)

6、EQ_REF、连接时使用primary key 或 unique类型
select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;

7、CONST、常量
表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
select nid from tb1 where nid = 2 ;

8、SYSTEM 系统
表仅有一行(=系统表)。这是const联接类型的一个特例。
select * from (select nid from tb1 where nid = 1) as A;

4、possible_keys、可能使用的索引

5、key_len、MySQL中使用索引字节长度

6、rows、mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值

7、extra、该列包含MySQL解决查询的详细信息

1、“Using index”
此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。

2、“Using where”
这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。

3、“Using temporary”
这意味着mysql在对查询结果排序时会使用一个临时表。

4、“Using filesort”
这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。

5、“Range checked for each record(index map: N)”
这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。

5.1、联合索引和单列索引测试

https://blog.csdn.net/Abysscarry/article/details/80792876

最后索引的使用及注意事项

EXPLAIN可以帮助开发人员分析SQL问题,explain显示了mysql如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语句。

使用方法,在select语句前加上Explain就可以了:

Explain select * from user where id=1;
尽量避免这些不走索引的sql:

SELECT sname FROM stu WHERE age+10=30;-- 不会使用索引,因为所有索引列参与了计算

SELECT sname FROM stu WHERE LEFT(date,4) <1990; – 不会使用索引,因为使用了函数运算,原理与上面相同

SELECT * FROM houdunwang WHERE uname LIKE’后盾%’ – 走索引

SELECT * FROM houdunwang WHERE uname LIKE “%后盾%” – 不走索引

– 正则表达式不使用索引,这应该很好理解,所以为什么在SQL中很难看到regexp关键字的原因

– 字符串与数字比较不使用索引;
CREATE TABLE a (a char(10));
EXPLAIN SELECT * FROM a WHERE a=“1” – 走索引
EXPLAIN SELECT * FROM a WHERE a=1 – 不走索引

select * from dept where dname=‘xxx’ or loc=‘xx’ or deptno=45 --如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引, 我们建议大家尽量避免使用or 关键字

– 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
索引虽然好处很多,但过多的使用索引可能带来相反的问题,索引也是有缺点的:

虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT,UPDATE和DELETE。因为更新表时,mysql不仅要保存数据,还要保存一下索引文件
建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在要给大表上建了多种组合索引,索引文件会膨胀很宽
索引只是提高效率的一个方式,如果mysql有大数据量的表,就要花时间研究建立最优的索引,或优化查询语句。

 使用索引时,有一些技巧:

1.索引不会包含有NULL的列

   只要列中包含有NULL值,都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此符合索引就是无效的。

2.使用短索引

   对串列进行索引,如果可以就应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

3.索引列排序

   mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作,尽量不要包含多个列的排序,如果需要最好给这些列建复合索引。

4.like语句操作

  一般情况下不鼓励使用like操作,如果非使用不可,注意正确的使用方式。like ‘%aaa%’不会使用索引,而like ‘aaa%’可以使用索引。

5.不要在列上进行运算

6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的

7.索引要建立在经常进行select操作的字段上。

   这是因为,如果这些列很少用到,那么有无索引并不能明显改变查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。

8.索引要建立在值比较唯一的字段上。

9.对于那些定义为text、image和bit数据类型的列不应该增加索引。因为这些列的数据量要么相当大,要么取值很少。

10.在where和join中出现的列需要建立索引。

11.where的查询条件里有不等号(where column != …),mysql将无法使用索引。

12.如果where字句的查询条件里使用了函数(如:where DAY(column)=…),mysql将无法使用索引。

13.在join操作中(需要从多个数据表提取数据时),mysql只有在主键和外键的数据类型相同时才能使用索引,否则及时建立了索引也不会使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值