您的位置:首页 > 数据库 > MySQL

MySQL数据库索引

2015-10-23 22:06 567 查看
 数据库索引好比是一本书前面的目录,能加快数据库的查询速度。索引分为聚簇索引非聚簇索引两种。聚簇索引 是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。

一、 索引的特点

Ø  索引可以加快数据库的检索速度

Ø  索引降低了数据库插入、修改、删除等维护任务的速度

Ø  索引创建在表上,不能创建在视图上

Ø  索引既可以直接创建,也可以间接创建

Ø  可以在优化隐藏中,使用索引

Ø  使用查询处理器执行SQL语句,在一个表上,一次只能使用一个索引

 

二、根据数据库的功能,可以在数据库设计器中创建三种索引:唯一索引、主键索引和聚集索引。

 最普通的情况,是为出现在where子句的字段建一个索引。为方便讲述,先建立一个如下的表。

CREATE TABLE mytable(

id primary key,

category_id int not null default 0,

user_id int not null default 0,

adddate int not null default 0

);

如果在查询时常用类似以下的语句:

SELECT * FROM mytable WHERE category_id=1;

最直接的应对之道,是为category_id建立一个简单的索引:

CREATE INDEX mytable_categoryid ON mytable (category_id);

OK.如果有不止一个选择条件呢?例如:

SELECT * FROM mytable WHERE category_id=1 AND user_id=2;

第一反应可能是,再给user_id建立一个索引。不好,这不是一个最佳的方法。可以建立多重的索引。

CREATE INDEX mytable_categoryid_userid ONmytable(category_id,user_id);

可以使用EXPLAIN查看使用索引的情况

 

三、添加索引的方法

1.      添加PRIMARY KEY(主键索引)

ALTER TABLE`table_name` ADD PRIMARY KEY ( `column` )

2.      添加UNIQUE(唯一索引)

ALTER TABLE`table_name` ADD UNIQUE ( `column` )

3.      添加INDEX(普通索引)

ALTER TABLE`table_name` ADD INDEX index_name ( `column` )

或者 CREATE INDEXindex_name ON table_name (column);

4.      添加FULLTEXT(全文索引)

ALTER TABLE `table_name`ADD FULLTEXT ( `column`)

5.      添加多列索引

ALTER TABLE`table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )

或者 CREATE INDEXindex_name ON table_name (column1, column2, column3);

 

四、有两种基本的索引结构,也就是索引文件的保存方式,一个是顺序索引,就是根据值的顺序排序的(这个文件里面的值,也就是为其建索引的字段值,是顺序的放在索引文件里面),另外一个是散列索引,就是将值平均分配到若干散列桶中,通过散列函数定位的。

Ø  顺序索引分为两类,单级索引(不怎么用)和多级索引(通常是B+树,大量使用)。

Ø  如果被索引的字段本身按照一定的顺序排序,那么这种索引叫做聚集索引,否则叫做非聚集索引。如果被索引的字段的每个值都有一个索引与其对应,那么这种索引叫做稠密索引,否则叫做稀疏索引。

Ø  单级索引就是把所有的索引字段以及对应的文件位置按顺序一个个的排列出来,这种索引查找起来比较慢,因为是顺序存储的,可以使用二分查找法,但是总体来说效率不高,这种索引是最基础的索引,一般不用。

Ø  多级索引实际上就是在单级索引之上再加索引(稀疏索引),也就是指向索引的索引,二级索引上面还可以再加三级索引,可以不停的加,加到最后最上层只剩下一个节点(根节点),就成了一个树状结构了。我们经常听到B+树就是这个概念,用B+树的目的和红黑树差不多,也是为了尽量保持树的平衡,当然红黑树是二叉树,但B+树就不是二叉树了,节点下面可以有多个子节点,数据库开发商会设置子节点数的一个最大值,这个值不会太小,所以B+树一般来说比较矮胖,而红黑树就比较瘦高了。

 

五、联合索引

联合索引又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c),可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找。当最左侧字段是常量引用时,索引就十分有效。

两个或更多个列上的索引被称作复合索引。

利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。

所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。

如:建立姓名、年龄、性别的复合索引。

create table test(

a int, b int,  c int,  KEY a(a,b,c)

);

 

优: select * from test where a=10 and b>50

差: select * from test where a50

 

优: select * from test order by a

差: select * from test order by b

差: select * from test order by c

 

优: select * from test where a=10 order by a

优: select * from test where a=10 order by b

差: select * from test where a=10 order by c

 

优: select * from test where a>10 order by a

差: select * from test where a>10 order by b

差: select * from test where a>10 order by c

 

优: select * from test where a=10 and b=10 order by a

优: select * from test where a=10 and b=10 order by b

优: select * from test where a=10 and b=10 order by c

 

优: select * from test where a=10 and b=10 order by a

优: select * from test where a=10 and b>10 order by b

差: select * from test where a=10 and b>10 order by c

 

索引原则

1.      索引越少越好

原因:主要在修改数据时,每个索引都要进行更新,降低写速度。

2.      最窄的字段放在键的左边

3.      避免file sort排序,临时表和表扫描

 

六、前缀索引

MySQL 前缀索引能有效减小索引文件的大小,提高索引的速度。但是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用作覆盖索引(Covering Index)。

# 语法

ALTER TABLE table_name ADDKEY(column_name(prefix_length));

# 示例

ALTER TABLE city ADD KEY(cityname(7));

 

计算全列选择性的一个例子

# 全列选择性

SELECT COUNT(DISTINCT column_name) /COUNT(*) FROM table_name;

 

# 测试某一长度前缀的选择性

SELECT COUNT(DISTINCT LEFT(column_name,prefix_length)) / COUNT(*) FROM table_name;

 

应用场景示例:

数据库里有个地址(address)字段,类型为varchar(100),业务决定了要经常根据address来进行查询。

确定选择性:

Sql代码

SELECT count(DISTINCT(address))/count(*) ASSelectivity FROM info;  

+-------------+   

| Selectivity |  

+-------------+    

| 0.8745 |  

+-------------+  

<address>选择性很好,但是长度为100,对整个字段建立索引显然不合适,可以考虑建立前缀索引,例如<left(address,5)>,看看其选择性: 

Sql代码

SELECTcount(DISTINCT(left(address,5)))/count(*) AS Selectivity FROM info;  

+-------------+   

| Selectivity |  

+-------------+   

| 0.5981 |  

+-------------+   

选择性还不错,但和0.8745相比还是太低,所以我们可以将前缀长度增加到10,再看看选择性:

Sql代码

SELECTcount(DISTINCT(left(address,10)))/count(*) AS Selectivity FROM info;  

+-------------+   

| Selectivity |  

+-------------+   

| 0.8239 |  

+-------------+  

和0.8745已经很接近了,但是索引长度只有10,所以就可以决定建立前缀索引了。

 

七、 覆盖索引

Ø  就是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。

Ø  索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引。

Ø  是非聚集复合索引的一种形
b337
式,它包括在查询里的Select、Join和Where子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段,也即,索引包含了查询正在查找的数据)。

 

覆盖索引用通俗的话讲就是在select的时候只用去读取索引而取得数据,无需进行二次select相关表。这样的索引的叶子节点上面也包含了他们索引的数据。

select * from table_name;

select id,name fromtable_name;

在多数情况下,我们只应该去查询我们有必要知道的列,这样一来网络之间传送的数据包小了,减少了网络通信,查询的速度自然会得到提升。

select a from table_name where b ...; 这样的一个查询,都知道索引应该加在b上面,

查询的处理过程:

首先去检索b索引找到与其对应的索引à 然后根据索引区检索正确的数据行。

这样一来一去就是两次检索,能不能通过一次检索而得到数据呢?

如果希望通过一次检索得到数据,那么索引上面就应该包含其索引相对的数据,这样可能吗?

当然可能.

alter table_name add index index_name(b,a);

【该联合索引即为覆盖索引,即建索引的字段正好是覆盖查询条件中所涉及的字段,也即,索引包含了查询正在查找的数据】

查看是否使用了覆盖索引;

explain select ·····;

... ...

extra:use index

如果出现了上述” extra:use index”字体部分,就表示使用了覆盖索引。

注意:覆盖索引也并不适用于任意的索引类型,索引必须存储列的值。Hash 和full-text索引不存储值,因此MySQL只能使用B-TREE。并且不同的存储引擎实现覆盖索引都是不同的。并不是所有的存储引擎都支持它们。如果要使用覆盖索引。一定要注意SELECT 列表值取出需要的列。不可以是SELECT * ,因为如果将所有字段一起做索引会导致索引文件过大。查询性能下降。不能为了利用覆盖索引而这么做。

InnoDB中,覆盖索引查询时除了除了索引本身的包含的列,还可以使用其默认的聚集索引列 。这跟INNOB的索引结构有关系。主索引是B+树索引存储。也即我们所说的数据行即索引。索引即数据。这个相对的是主键索引。对于INNODB的辅助索引。它的叶子节点存储的是索引值和指向主键索引的位置。然后需要通过主键在查询表的字段值。所以辅助索引存储了主键的值。覆盖索引也可以用上INNODB默认的聚集索引。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MySQL 索引 数据库