MySQL索引的建立与实现
一、索引介绍
1.MySQL中,所有的数据类型都可以被索引,索引包括普通索引,唯一性索引,全文索引,单列索引,多列索引和空间索引等。
2.额外的:我已知的自动创建索引的时机:创建主键,唯一,外键约束的时候
3. 索引优点:提高查询,联合查询,分级和排序的时间
索引缺点:索引占空间,维护(创建,更新,维护)索引时需要耗费时间
1、创建普通索引
CREATE TABLEindex1 (id INT,
name VARCHAR(20),
sex BOOLEAN,
INDEX(id)
);
SHOW CREATETABLE index1\G;
2、创建唯一性索引
CREATE TABLEindex2(id INT UNIQUE,
name VARCHAR(20),
UNIQUE INDEX index2_id(id ASC)
);
SHOW CREATETABLE index2\G;
看到在字段id上建立了两个唯一索引id和index2_id,当然这样是没有必要的。
3、创建全文索引
CREATE TABLEindex3 (id INT,
info VARCHAR(20),
FULLTEXT INDEX index3_info(info)
) ENGINE=MyISAM;
4.MySQL索引底层主要通过B+树实现
二、索引实现原理
MySQL索引的定义为:
索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。
数据库查询是数据库的最主要功能之一。
我们都希望查询数据的速度能尽可能的快。最基本的查询算法当然是顺序查找(linear search),这种复杂度为O(n)的算法在数据量很大时显然是糟糕的,好在计算机科学的发展提供了很多更优秀的查找算法,例如二分查找(binary search)、二叉树查找(binary tree search)等。但是数据本身的物理组织结构不可能完全满足各种数据结构,所以,在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
举个例子:
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找在的复杂度内获取到相应数据。
虽然这是一个货真价实的索引,但是实际的数据库系统几乎没有使用二叉查找树或其进化品种红黑树(red-black tree)实现的,原因会在下文介绍。
B树是什么,B+树呢
首先要搞懂平衡二叉树是什么,平衡二叉树:在二叉搜索树(叫排序树也行)基础上,进行平衡之后的树,所谓“平衡”,说的是这棵树的各个分支的高度是均匀的,它的左子树和右子树的高度之差绝对值小于1,这样就不会出现一条支路特别长的情况。于是,在这样的平衡树中进行查找时,总共比较节点的次数不超过树的高度,这就确保了查询的效率(时间复杂度为O(logn))。
B树事实上是一种平衡的多叉查找树,也就是说最多可以开m个叉(m>=2),我们称之为m阶b树。
查询图中字母表中的K
1. 从根节点P开始,K的位置在P之前,进入左侧指针
2. 左子树中,依次比较C、F、J、M,发现K在J和M之间
3. 沿着J和M之间的指针,继续访问子树,并依次进行比较,发现第一个关键字K即为指定查找的值
与B-Tree相比,B+Tree有以下不同点:
每个节点的指针上限为2d而不是2d+1。
内节点不存储data,只存储key;叶子节点不存储指针。
图3是一个简单的B+Tree示意。
带有顺序访问指针的B+Tree
数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增加了顺序访问指针。
图4
如图4所示,在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能,例如图4中如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率。
为什么采用B/B+树?
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,而B+Tree的高度低(多叉树),可以减少I/O次数。对于数据库来说,每进入一层,就要从硬盘读取一次数据,这非常致命,因为硬盘的读取时间远远大于数据处理时间,数据库读取硬盘的次数越少越好。
MySQL索引实现
MyISAM索引实现
MyISAM引擎使用带有顺序访问指针的B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。如下图
以Col1为主键,则上图是一个MyISAM表的主索引(Primarykey)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示:
MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。
InnoDB索引实现
InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。、InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。
很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大
索引优化
1、建立索引加快查询性能,优先在经常搜索的字段上建立索引(where)
2、应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
3、in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
4、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
5、尽量选择小而简单的数据类型做索引,减少磁盘空间
6、有时候需要索引很长的字符列,这会让索引变得大且慢。一个方式是使用哈希索引,另一个是使用前缀索引,即索引开始的部分字符串,这样可以节约索引空间,提高效率。