【索引】索引的作用?为什么能够提高查询速度?以及索引用法(索引的原理)

 

MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。

打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。

索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。

创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。

实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。

上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

建立索引会占用磁盘空间的索引文件。 

 

为什么能够提高查询速度?

索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。
一般的顺序查找,复杂度为O(n),而二分查找复杂度为O(log2n)。当n很大时,二者的效率相差及其悬殊。

举个例子:
表中有一百万条数据,需要在其中寻找一条特定id的数据。如果顺序查找,平均需要查找50万条数据。而用二分法,至多不超过20次就能找到。二者的效率差了2.5万倍!

 

在一个或者一些字段需要频繁用作查询条件,并且表数据较多的时候,创建索引会明显提高查询速度,因为可由全表扫描改成索引扫描。

(无索引时全表扫描也就是要逐条扫描全部记录,直到找完符合条件的,索引扫描可以直接定位)

 

不管数据表有无索引,首先在SGA的数据缓冲区中查找所需要的数据,如果数据缓冲区中没有需要的数据时,服务器进程才去读磁盘。
1、无索引,直接去读表数据存放的磁盘块,读到数据缓冲区中再查找需要的数据。
2、有索引,先读入索引表,通过索引表直接找到所需数据的物理地址,并把数据读入数据缓冲区中。

 

索引有什么副作用吗?

(1)索引是有大量数据的时候才建立的,没有大量数据反而会浪费时间,因为索引是使用二叉树建立.

(2)当一个系统查询比较频繁,而新建,修改等操作比较少时,可以创建索引,这样查询的速度会比以前快很多,同时也带来弊端,就是新建或修改等操作时,比没有索引或没有建立覆盖索引时的要慢。

(3)索引并不是越多越好,太多索引会占用很多的索引表空间,甚至比存储一条记录更多。
对于需要频繁新增记录的表,最好不要创建索引,没有索引的表,执行insert、append都很快,有了索引以后,会多一个维护索引的操作,一些大表可能导致insert 速度非常慢。

 

 

 

例子:

 

 

 建立索引:(在username列建立索引)

ALTER table tableName ADD INDEX indexName(username)

 利用explain分析索引:    参考 :http://www.cnblogs.com/qlqwjy/p/7767479.html

 1.没有查询username(不用索引)

EXPLAIN SELECT * FROM USER

 

 

2.根据username进行比对:(使用索引) 

EXPLAIN SELECT * FROM USER WHERE username='qlq'

 

 

 

 

 

 索引用法:

普通索引
创建索引

这是最基本的索引,它没有任何限制。它有以下几种创建方式:

CREATE INDEX indexName ON mytable(username(length)); 

    如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。
修改表结构(添加索引)

    ALTER table tableName ADD INDEX indexName(columnName)

创建表的时候直接指定

CREATE TABLE mytable(  
 
ID INT NOT NULL,   
 
username VARCHAR(16) NOT NULL,  
 
INDEX [indexName] (username(length))  
 
);  

删除索引的语法

DROP INDEX [indexName] ON mytable; 

ALTER TABLE `exam5`.`questions` DROP KEY `question_type_index`; 唯一索引 它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式: 创建索引 CREATE UNIQUE INDEX indexName ON mytable(username(length)) 修改表结构 ALTER table mytable ADD UNIQUE [indexName] (username(length)) 创建表的时候直接指定 CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(
16) NOT NULL, UNIQUE [indexName] (username(length)) ); 使用ALTER 命令添加和删除索引 有四种方式来添加数据表的索引: ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。 ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。 ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。 ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。 以下实例为在表中添加索引。 mysql> ALTER TABLE testalter_tbl ADD INDEX (c); 你还可以在 ALTER 命令中使用 DROP 子句来删除索引。尝试以下实例删除索引: mysql> ALTER TABLE testalter_tbl DROP INDEX c; 使用 ALTER 命令添加和删除主键 主键只能作用于一个列上,添加主键索引时,你需要确保该主键默认不为空(NOT NULL)。实例如下: mysql> ALTER TABLE testalter_tbl MODIFY i INT NOT NULL; mysql> ALTER TABLE testalter_tbl ADD PRIMARY KEY (i); 你也可以使用 ALTER 命令删除主键: mysql> ALTER TABLE testalter_tbl DROP PRIMARY KEY; 删除主键时只需指定PRIMARY KEY,但在删除索引时,你必须知道索引名。 显示索引信息 你可以使用 SHOW INDEX 命令来列出表中的相关的索引信息。

 

mysql查看表索引

mysql> show index from tblname;

mysql> show keys from tblname;

· Table

表的名称。

· Non_unique

如果索引不能包括重复词,则为0。如果可以,则为1。

· Key_name

索引的名称。

· Seq_in_index

索引中的列序列号,从1开始。

· Column_name

列名称。

· Collation

列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。

· Cardinality

索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机 会就越大。

· Sub_part

如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。

· Packed

指示关键字如何被压缩。如果没有被压缩,则为NULL。

· Null

如果列含有NULL,则含有YES。如果没有,则该列含有NO。

· Index_type

用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。

· Comment

 

 

  参考:http://www.jb51.net/article/73372.htm

 

自己的实践:

1.单列建立索引

表名  questions

 结构:

 

未建立索引

  查看一个数据量非常大的试题表,根据试题的类型查:

SELECT * FROM questions WHERE TYPE='单选题'

 

结果:花费1062ms

/*[15:03:40][1062 ms]*/ SELECT * FROM questions WHERE TYPE='单选题'  LIMIT 0, 1000;    

 

 

 

用explain解释语句之后:

EXPLAIN SELECT * FROM questions WHERE TYPE='单选题'

结果:可以简单的看到一些参数,扫描了7134行,命中率大概为10%.

 

建立索引

 在type这一列建立索引

ALTER TABLE questions ADD INDEX index_ques_type(TYPE)

再次用explain分析执行语句

EXPLAIN SELECT * FROM questions WHERE TYPE='单选题'

 

结果: 扫描的行数明显减少,且命中率明显上升

 

2.建立组合索引

(1)未加索引

SELECT *
FROM questions
WHERE TYPE = '单选题'
    AND questionBankId = '40b7fedfbd1c4cc680d93782a033a518'

 

结果:

 

explain解释执行

EXPLAIN
SELECT *
FROM questions
WHERE TYPE = '单选题'
    AND questionBankId = '40b7fedfbd1c4cc680d93782a033a518'

  

 

 (2)建立多列索引

ALTER TABLE `exam5`.`questions` ADD INDEX `index_duolie` (`questionBankId`, `type`)

 

(3) 查询:(速度明显提高)

SELECT *
FROM questions
WHERE 
    questionBankId = '40b7fedfbd1c4cc680d93782a033a518' AND TYPE = '单选题'

 

 explain解释语句(使用了索引)

EXPLAIN
SELECT *
FROM questions
WHERE 
    questionBankId = '40b7fedfbd1c4cc680d93782a033a518' AND TYPE = '单选题'
    

  

 

 (4)查看索引

SHOW INDEX FROM questions

 

 

(5)使用单列索引中的一列

  1.只使用questionBankId 这一列看到查询时使用了索引

EXPLAIN
SELECT *
FROM questions
WHERE 
    questionBankId = '40b7fedfbd1c4cc680d93782a033a518'

 

 

  2.只使用type这一列没有使用索引

EXPLAIN
SELECT *
FROM questions
WHERE TYPE = '单选题'

  

  3 type和questionBankId交换位置使用索引

EXPLAIN
SELECT *
FROM questions
WHERE TYPE = '单选题'  AND questionBankId = '40b7fedfbd1c4cc680d93782a033a518'

  

  

总结:对于单列索引,使用where条件就可以进行查询

  对于多列索引(A,B),如果where中只有A可以起到作用,只有B不会使用索引,A、B都有会使用索引,也就是在有A的条件下才会使用索引。

 

 

 

 

 

参考:

  http://www.runoob.com/mysql/mysql-index.html

 

posted @ 2017-11-01 16:52  QiaoZhi  阅读(7579)  评论(0编辑  收藏  举报