目录
概述
什么是索引
索引是对数据库表中一个或多个列的值进行排序的结构,使用索引可快速访问数据库表中的特定信息。通俗的讲,索引就相当于目录。
索引的优缺点
优点:
- 可以大大加快数据的检索速度,这也是创建索引的最主要的原因
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义
- 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
缺点:
- 索引需要额外的维护成本;因为索引文件是单独存在的文件,对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。
MySQL中
索引的基本用法
创建索引
第一种, 使用CREATE INDEX 命令(但是,不能创建PRIMARY KEY索引)
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type] ON tbl_name (index_col_name, ...)
其中index_col_name格式:
col_name[(length)][ASC|DESC]
SPATIAL 表示空间索引,不常用
第二种,是用 ALTER TABLE命令去增加索引
ALTER TABLE tbl_name ADD INDEX index_name(index_col_name, ...) 添加普通索引,索引值可出现多次
ALTER TABLE tbl_name ADD UNIQUE INDEX index_name(index_col_name, ...) 创建的索引值必须是唯一的(除了NULL外)
ALTER TABLE tbl_name ADD PRIMARY KEY INDEX index_name(index_col_name, ...) 该语句添加了一个主键,索引值必须唯一,不能为NULL
ALTER TABLE tbl_name ADD FULLTEXT INDEX index_name(index_col_name, ...) 指定了索引为FULLTEXT,用于全文索引
第三种,在创建表时,直接指定
CREATE TABLE tbl_name(
column_name_1 column_type_1 constraints,
column_name_2 column_type_2 constraints,
...
INDEX [index_name] (col_name[(length)][ASC|DESC])
);
删除索引
DROP INDEX index_name ON tbl_name
测试索引
MySQL中使用explain语句,查看执行计划,例如
explain select * from test where name = 'Tom' \G
SQL SEERVER中
索引的基本用法
创建索引
创建聚集索引
方法一
alter table <table_name> add constraint <constraint_name> primary key (columnName ASC|DESC, ...) with (drop_existing = on)
- with(drop_existing = on|off); 加上这个的意思是如果这个索引还在表上就drop 掉然后在create 一个新的。特别是在聚集索引上用使用这个就可以不会引起非聚集索引的重建。
- with(online = on|off); 创建索引时用户也可以访问表中的数据,
- with(pad_index = on|off fillfactor = 80); fillfactor 用来设置填充百分比,pad_index 只是用来连接fillfactor 但是它又不难少,这点无语了。
- with(allow_row_locks = on|off | allow_page_locks = on |off); 是否允许页锁 or 行锁
- with(data_compression = row | page ); 这样可以压缩索引大小
注意
用下面的方式删除索引:
drop index <index_name> on <table_name>
若对唯一键生成的索引直接删除,会出现下面错误:
An explicit DROP INDEX is not allowed on index ‘…’. It is being used for PRIMARY KEY constraint enforcement.
正确的做法,删除表约束:
alter table <table_name> drop constraint <index_name>
方法二:
create clustered index <index_name> on <table_name>(column_name ASC|DESC, ...) with (drop_existing = on)
创建复合索引
create index <index_name> on <table_name>(column_name ASC|DESC, ...) with (drop_existing = on)
一般是使用多个列
创建覆盖索引
create index index_name on table_Name (columnName ASC|DESC[,......]) include(column_Name_List)with (drop_existing = on);
首先,覆盖索引它只是非聚集索引的一种特别形式,下文说的非聚集索引不包涵覆盖索引,当然这个约定只适用于这一段话,这样做的目的是为了说明各中的区别。
首先:
1、非聚集索引不包含数据,通过它找到的只是文件中数据行的引用(表是堆的情况下)或是聚集索引的引用,SQL Server要通这个引用去找到相应的数据行。
2、正因为非聚集索引它没有数据,才引发第二次查找。
3、覆盖索引就是把数据加到非聚集索引上,这样就不需要第二次查找了。这是一种以空间换性能的方法。非聚集索引也是。只是做的没有它这么出格。
创建唯一索引
create unique index <index_name> on <table_name>(column_name ASC|DESC, ...) with (drop_existing = on)
注意
- 如果在列上有重复值,就不可以在这个列上定义,唯一索引。
- 定义唯一索引后相应的列上不可以插入重复值。
查看索引
SQL Server中查看一个表中有哪些索引
execute sp_helpindex @objname = '<table_name>'
SQL Server中查看具体的索引相关信息
DBCC show_statistics( '<table_name>', '<index_name>')
上面这条语句,会查出三种信息,用来分析目标索引
select * from sysindexes where name = '<index_name>'
MySQL设计索引的原则
- 搜索的索引列。最适合的索隐列是出现在where子句中的列
- 使用唯一索引。考虑某列中值得分布。索引列的基数越大,索引的效果越好。
- 使用短索引。如果对字符串列进行索引,应该指定一个前缀长度,目的是索引高速缓存中的块能容纳更多的键值。
- 利用最左前缀。在创建一个n列的索引时,实际上是创建了可用的n个索引,多列索引可起几个索引的作用,因为可以利用索引中最左边的列集来匹配行。这样的列集称为最左前缀。
- 不要过度使用索引。
SQL Server索引设计原则
请参考msdn的官方文档
索引的数据结构
索引的数据结构是B树,B树是一种用于查找的平衡多叉树
聚集索引和非聚集索引
非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据
为了提高某个属性(或属性组)的查询速度,把这个或这些属性(称为聚集码)上具有相同值的元组集中存放在连续的物理块称为聚集。
在SQL SERVER中,聚集的作用就是将某一列(或是多列)的物理顺序改变为和逻辑顺序相一致. 聚集索引的存储是以B树存储,B树的叶子直接存储聚集索引的数据. 因为聚集索引改变的是其所在表的物理存储顺序,所以每个表只能有一个聚集索引.
因为每个表只能有一个聚集索引,如果我们对一个表的查询不仅仅限于在聚集索引上的字段。我们又对聚集索引列之外还有索引的要求,那么就需要非聚集索引了.
非聚集索引,本质上来说也是聚集索引的一种.非聚集索引并不改变其所在表的物理结构,而是额外生成一个聚集索引的B树结构,但叶子节点是对于其所在表的引用,这个引用分为两种,如果其所在表上没有聚集索引,则引用行号。如果其所在表上已经有了聚集索引,则引用聚集索引的页.
非聚集索引需要额外的空间进行存储,按照被索引列进行聚集索引,并在B树的叶子节点包含指向非聚集索引所在表的指针.
通过非聚集索引的原理可以看出,如果其所在表的物理结构改变后,比如加上或是删除聚集索引,那么所有非聚集索引都需要被重建,这个对于性能的损耗是相当大的。所以最好要先建立聚集索引,再建立对应的非聚集索引.
复合索引的使用
必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引。
例子
例如索引包括三个字段(a, b, c),只有下面三种方式,才能使用到该索引:
where a= ? and b = ? and c = ?
where a=? and b=?
where a=?