一、索引简介
1 问题
随着业务的增长,数据库中的数据越来越庞大,数据查询所需要的时间也越来越长。那如何保证数据增长的同时,数据查询时间不变呢?
2 概念
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。
索引的一个主要目的就是加快检索表中数据的方法,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构。
3 索引结构
Mysql索引主要有两种结构:B-Tree索引和Hash索引.
二、索引添加方式
2.1 介绍
主键索引:它是一种特殊的唯一索引,不允许有空值。
ALTER TABLE table_name ADD PRIMARY KEY(column)
唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。(唯一是约束条件)
ALTER TABLE table_name ADD UNIQUE(column)
普通索引:最基本的索引,没有任何限制(尽量选择差别较大的字段)
ALTER TABLE table_name ADD INDEX index_name(column)
前缀索引: 只用已字段的前几个字符作为索引.(1、索引是存储与内存空间,2、适用于前几个字符差距加大的字段)
ALTER TABLE table_name ADD INDEX index_name(column(6))
全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间。
ALTER TABLE table_name ADD FULLTEXT(column)
组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。创建复合索引时应该将最常用(频率)作限制条件的列放在最左边,依次递减。(推荐,尽量多使用)
ALTER TABLE table_name ADD INDEX index_name(column1,column2,column3)
2.2 删除索引
ALTER TABLE table_name DROP INDEX index_name 例如: alter table yu_test drop index id_status # 删除yu_test 表里面的索引名为id_status
2.3 组合索引使用
index idx(a,b,c(8)) # 组合索引a,b,c(8), c前缀索引 select * from table where a,b,c ------> 使用了a,b,c 三个索引 select * from table where a,b ------> 使用了a,b 两个索引 select * from table where a,c. ------> 使用了a索引 select * from table where a -------> 使用了a索引
2.4 注意
# 1、尽量多的使用组合,少用单索引(索引占内存) # 2、使用频繁的数据,要尽量放在组合索引的最前面 # 3、尽量少在sql语句中使用函数. # 4、select * from table. 尽量使用limit,否则数据查询会很慢
三、判断是否应该建索引的条件
1、较频繁的作为查询条件的字段应该创建索引。
2、唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件。
3、增、删、改操作较多的数据库字段不适合建索引。
四、建立索引需遵循的原则
1、越小的数据类型通常更好
越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
2、简单的数据类型更好
整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
3、尽量避免NULL
应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
五、索引优化--explain
1 每当创建完数据库表和索引之后,以应该问自己以下几个问题:
创建的索引是否能够满足绝大多数的查询?
索引的区分度是否足够大?
组合索引的字段是否过多?是否存在区分度不高的字段?
索引有没有提高效率的空间?
前三个问题,一般凭借DBA或者开发人员的经验来进行甄别,或者在实际测试或者使用中进行优化。
但是索引有没有提高效率的空间?这个问题是可以通过MySQL的explain命令来进行优化指导的。
2、explain 使用。
使用方法,在select语句前加上explain就可以了。
3、explain列的解释
id | SELECT识别符。这是SELECT的查询序列号 |
select_type |
SELECT类型,可以为以下任何一种:SIMPLE:简单SELECT(不使用UNION或子查询);
PRIMARY:最外面的SELECT;
UNION:UNION中的第二个或后面的SELECT语句;
DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询;
UNION RESULT:UNION 的结果;SUBQUERY:子查询中的第一个SELECT;
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询;
DERIVED:导出表的SELECT(FROM子句的子查询);
|
table |
输出的行所引用的表
|
type |
联接类型。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序:(需用)
|
possible_keys |
指出MySQL能使用哪个索引在该表中找到行
|
key |
显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
|
key_len |
显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL (越短越优)
|
ref | 显示使用哪个列或常数与key一起从表中选择行 |
rows | 显示MySQL认为它执行查询时必须检查的行数。多行之间的数据相乘可以估算要处理的行数。 |
filtered | 显示了通过条件过滤出的行数的百分比估计值。 |
Extra | 该列包含MySQL解决查询的详细信息。 |
名称 | 含义 |
---|---|
system | 表仅有一行(=系统表)。这是const联接类型的一个特例。(最优) |
const | 表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次!(最优) |
eq_ref | 对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。(等值条件才有可能出现) |
ref | 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。 |
range | 只检索给定范围的行,使用一个索引来选择行。(部分索引扫描) |
index | 该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。(全索引操作) |
ALL | 对于每个来自于先前的表的行组合,进行完整的表扫描。(全表扫描) |
名称 | 含义 |
---|---|
Distinct | MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。 |
Not exists | MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。 |
range checked for each record (index map: #) | MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。 |
Using filesort | MySQL需要额外的一次传递,以找出如何按排序顺序检索行。 |
Using index | 从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。 |
Using temporary | 为了解决查询,MySQL需要创建一个临时表来容纳结果。 |
Using where | WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。 |
Using sort_union(...), Using union(...), Using intersect(...) | 这些函数说明如何为index_merge联接类型合并索引扫描。 |
Using index for group-by |
类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY 或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。 |