在大型数据中一张表中要容纳几万、几十万、甚至上百万的数据,而当这些表与其他表连接后,所得到的新的数据数目更是大大超过原来的表。当用户检索这么大量的数据时,经常会感觉到慢。这个时候要提高数据库的检索性能,就必须要用到索引。给表追加合适的索引能极大的改善检索的效率,提高数据库性能。
什么是索引
在认识索引之前,我们先了解一下对于没有索引的表示如何进行检索的。例如:
SELECT * FROM employee WHERE name=’wang’;
在默认的状态下,表中的记录是没有顺序的。也就是说,符合条件的数据保存在表中的什么位置,我们并不知道。这时候,数据库首先会从第一条记录开始检索。
但是,检索进行的过程中,找到了一个叫wang的人,并不意味着找到了所有叫wang的人。因为在数据库中叫wang的人可能只有一个,也可能有两个以上。因此,结果是要将表中的搜有记录都比较一遍。这个通常称为全表扫描。
为了解决这个问题,引入了索引的概念。索引顾名思义就是表中所有记录的搜索引导。类似于一本书的目录。
书籍的命令是按照一定的顺序来组织的。数据库中索引也是相同的做法。针对上面的表employee来,如果给name加了索引。名字索引就是在数据库中保存了姓名与包含此姓名的记录位置信息的集合(set)。这样,不用对整个表进行扫描就可以立即检索出结果。
索引的内部构造
实际运行中如果以表格的形式来管理索引,肯定不是一个有效率的方法。如果以表格的形式来保存索引,数据库的检索对象只是从一般的表变成保存索引的表,矛盾还是没有讲解。这里在大多数数据库中用了一种称为B树(Balanced Tree,平衡树)的结构来保存索引。
B树
枝叶扩散开来的树状结构。各个节点中保留着复合关键字以及指针组成的数组。指针当然是确定数据位置的信息,节点就是由这些指针相互关联起来。
在B树中,一个显著的特征是从根节点到各个叶子节点的距离都相等。这样,检索任何值时都经过相同数目的节点,能提高检索效率。
索引的设置与分析
创建索引时使用CREATE INDEX命令,CREATE INDEX命令语法如下:
CREATE [UNIQUE] INDEX 索引名 ON 表名(列名,….); #CREATE 不能建立主键索引
ALTER TABLE table_name add INDEX[UNIQUE] index_name(colnum)
删除索引
DROP INDEX 索引名 ON 表名
创建多列构成的复合索引及唯一性索引
索引可以含有多个列。例如,使用以下SQL语句创建列lname、fname的索引。
CREATE INDEX in_name ON employee(lname,fname);
这样的索引被称为复合索引。
分析索引优劣
使用EXPLAIN/DESC命令来确认 索引的使用情况
如果遍历的次数与创建索引索引前的变化不大,则说明创建索引时选择的列名不合理,需要选择合适的列重建索引。这正是分析索引优劣的方法。
索引的优点
极大地加快了查询,减少扫描和锁定的数据行数
索引的缺点
占用磁盘空间,减慢了数据更新速度。
添加索引有如下原则
1、为经常需要排序和联合操作的字段建立索引
2、为常作为查询条件的字段建立索引
3、不要给大字段类型(text等)加索引
索引失效的场合总结
为表追加了索引后,并不能保证在每次检索时都会使用列索引。如果SQL检索语句编写不当,就会出现无法使用索引的情况。此处归纳一些无法使用索引的情况,以帮助用户创建更合适的索引以及编写更有效率的SELECT检索语句。
1、 进行后方一致/部分一致检索的场合
下列的SQL检索语句是不能使用索引的。
a) SELECT * FROM employee WHERE name LIKE “%w%”;
b) SELECT * FROM employee WHERE name LIKE “%w”;
2、 使用了IS NOT NULL、[<>]比较运算符的场合
使用了IS NOT NULL、[<>]比较运算符的场合也是不能使用索引的。例如,下面的检索语句就不能使用索引。
SELECT * FROM employee WHERE name IS NOT NULL;
SELECT * FROM employee WHERE name <>’wang’;
3、 对列使用了运算/函数的场合
对索引使用了函数或进行了某些运算的情况,也是不能使用索引的。下面的检索语句检索了所有出生在1980年的员工,由于使用了YEAR函数,所以就不能使用索引了。
SELECT * FROM employee WHERE YEAR(birth) = ‘1980’;
4、 复合索引的第一列没有包含在WHERE条件语句中的场合
例如,针对表employee我们创建了以下复合索引。
CREATE INDEX in_index ON employee(lname,fname);
针对这个索引,如果我们单独检索lname列,或者同时检索lname与fname列时,该索引是会被使用到的。即执行以下检索语句将使用到此索引。
SELECT * FROM employee WHERE lname= ‘wang’ AND fname=’xiao’;
SELECT * FROM employee WHERE lname=’wang’;
而下面的检索语句则不能使用此索引。
SELECT * FROM employee WHERE fname=’xiao’;
SELECT * FROM employee WHERE lname=’wang’ OR lname=’xiao’;
前一条语句中索引的第一列没有包含在检索条件中,后一条检索语句看起来好像是包含了所有的索引列,但由于使用了OR关键字,检索条件的后面半句还是要对fname列进行单独检索。