MySQL目前主要有如下几种索引类型:
1.普通索引
2.惟一索引
3.主键索引
4.组合索引
5.全文索引html
<pre>CREATE TABLE table_name[col_name data type]
unique|fulltextindex_name[asc|desc]
</pre>node
1.unique|fulltext为可选参数,分别表示惟一索引、全文索引
2.index和key为同义词,二者做用相同,用来指定建立索引
3.col_name为须要建立索引的字段列,该列必须从数据表中该定义的多个列中选择
4.index_name指定索引的名称,为可选参数,若是不指定,默认col_name为索引值
5.length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度
6.asc或desc指定升序或降序的索引值存储mysql
1.普通索引
是最基本的索引,它没有任何限制。它有如下几种建立方式:
(1)直接建立索引算法
<pre>CREATE INDEX index_name ON table(column(length))
</pre>sql
(2)修改表结构的方式添加索引数据库
<pre>ALTER TABLE table_name ADD INDEX index_name ON (column(length))
</pre>segmentfault
(3)建立表的时候同时建立索引缓存
<pre>CREATE TABLE table
(数据结构
`id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `content` text CHARACTER NULL , `time` int(10) NULL DEFAULT NULL , PRIMARY KEY (`id`), INDEX index_name (title(length))
)
</pre>架构
(4)删除索引
<pre>DROP INDEX index_name ON table
</pre>
2.惟一索引
与前面的普通索引相似,不一样的就是:索引列的值必须惟一,但容许有空值。若是是组合索引,则列值的组合必须惟一。它有如下几种建立方式:
(1)建立惟一索引
<pre>CREATE UNIQUE INDEX indexName ON table(column(length))
</pre>
(2)修改表结构
<pre>ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))
</pre>
(3)建立表的时候直接指定
<pre>CREATE TABLE table
(
`id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `content` text CHARACTER NULL , `time` int(10) NULL DEFAULT NULL , UNIQUE indexName (title(length))
);
</pre>
3.主键索引
是一种特殊的惟一索引,一个表只能有一个主键,不容许有空值。通常是在建表的时候同时建立主键索引:
<pre>CREATE TABLE table
(
`id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) NOT NULL , PRIMARY KEY (`id`)
);
</pre>
4.组合索引
指多个字段上建立的索引,只有在查询条件中使用了建立索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合
<pre>ALTER TABLE table
ADD INDEX name_city_age (name,city,age);
</pre>
5.全文索引
主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。fulltext索引配合match against操做使用,而不是通常的where语句加like。它能够在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上能够建立全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,而后再用CREATE index建立fulltext索引,要比先为一张表创建fulltext而后再将数据写入的速度快不少。
(1)建立表的适合添加全文索引
<pre>CREATE TABLE table
(
`id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `content` text CHARACTER NULL , `time` int(10) NULL DEFAULT NULL , PRIMARY KEY (`id`), FULLTEXT (content)
);
</pre>
(2)修改表结构添加全文索引
<pre>ALTER TABLE article ADD FULLTEXT index_content(content)
</pre>
(3)直接建立索引
<pre>CREATE FULLTEXT INDEX index_content ON article(content)
</pre>
1.虽然索引大大提升了查询速度,同时却会下降更新表的速度,如对表进行insert、update和delete。由于更新表时,不只要保存数据,还要保存一下索引文件。
2.创建索引会占用磁盘空间的索引文件。通常状况这个问题不太严重,但若是你在一个大表上建立了多种组合索引,索引文件的会增加很快。
索引只是提升效率的一个因素,若是有大数据量的表,就须要花时间研究创建最优秀的索引,或优化查询语句。
使用索引时,有如下一些技巧和注意事项:
1.索引不会包含有null值的列
只要列中包含有null值都将不会被包含在索引中,复合索引中只要有一列含有null值,那么这一列对于此复合索引就是无效的。因此咱们在数据库设计时不要让字段的默认值为null。
2.使用短索引
对串列进行索引,若是可能应该指定一个前缀长度。例如,若是有一个char(255)的列,若是在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不只能够提升查询速度并且能够节省磁盘空间和I/O操做。
3.索引列排序
查询只使用一个索引,所以若是where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。所以数据库默认排序能够符合要求的状况下不要使用排序操做;尽可能不要包含多个列的排序,若是须要最好给这些列建立复合索引。
4.like语句操做
通常状况下不推荐使用like操做,若是非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可使用索引。
5.不要在列上进行运算
这将致使索引失效而进行全表扫描,例如
<pre>SELECT * FROM table_name WHERE YEAR(column_name)<2017;
</pre>
6.不使用not in和<>操做
本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别须要说明的是,MySQL支持诸多存储引擎,而各类存储引擎对索引的支持也各不相同,所以MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等。为了不混乱,本文将只关注于BTree索引,由于这是日常使用MySQL时主要打交道的索引,至于哈希索引和全文索引本文暂不讨论。
文章主要内容分为三个部分。
第一部分主要从数据结构及算法理论层面讨论MySQL数据库索引的数理基础。
第二部分结合MySQL数据库中MyISAM和InnoDB数据存储引擎中索引的架构实现讨论汇集索引、非汇集索引及覆盖索引等话题。
第三部分根据上面的理论基础,讨论MySQL中高性能使用索引的策略。
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就能够获得索引的本质:索引是数据结构。
咱们知道,数据库查询是数据库的最主要功能之一。咱们都但愿查询数据的速度能尽量的快,所以数据库系统的设计者会从查询算法的角度进行优化。最基本的查询算法固然是顺序查找(linear search),这种复杂度为O(n)的算法在数据量很大时显然是糟糕的,好在计算机科学的发展提供了不少更优秀的查找算法,例如二分查找(binary search)、二叉树查找(binary tree search)等。若是稍微分析一下会发现,每种查找算法都只能应用于特定的数据结构之上,例如二分查找要求被检索数据有序,而二叉树查找只能应用于二叉查找树上,可是数据自己的组织结构不可能彻底知足各类数据结构(例如,理论上不可能同时将两列都按顺序进行组织),因此,在数据以外,数据库系统还维护着知足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就能够在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
看一个例子:
图1
图1展现了一种可能的索引方式。左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并非必定物理相邻的)。为了加快Col2的查找,能够维护一个右边所示的二叉查找树,每一个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就能够运用二叉查找在O(log2n)O(log2n)的复杂度内获取到相应数据。
虽然这是一个货真价实的索引,可是实际的数据库系统几乎没有使用二叉查找树或其进化品种红黑树(red-black tree)实现的,缘由会在下文介绍。
目前大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree做为索引结构,在本文的下一节会结合存储器原理及计算机存取原理讨论为何B-Tree和B+Tree在被如此普遍用于索引,这一节先单纯从数据结构角度描述它们。
为了描述B-Tree,首先定义一条数据记录为一个二元组[key, data],key为记录的键值,对于不一样数据记录,key是互不相同的;data为数据记录除key外的数据。那么B-Tree是知足下列条件的数据结构:
d为大于1的一个正整数,称为B-Tree的度。
h为一个正整数,称为B-Tree的高度。
每一个非叶子节点由n-1个key和n个指针组成,其中d<=n<=2d。
每一个叶子节点最少包含一个key和两个指针,最多包含2d-1个key和2d个指针,叶节点的指针均为null 。
全部叶节点具备相同的深度,等于树高h。
key和指针互相间隔,节点两端是指针。
一个节点中的key从左到右非递减排列。
全部节点组成树结构。
每一个指针要么为null,要么指向另一个节点。
若是某个指针在节点node最左边且不为null,则其指向节点的全部key小于v(key1)v(key1),其中v(key1)v(key1)为node的第一个key的值。
若是某个指针在节点node最右边且不为null,则其指向节点的全部key大于v(keym)v(keym),其中v(keym)v(keym)为node的最后一个key的值。
若是某个指针在节点node的左右相邻key分别是keyikeyi和keyi+1keyi+1且不为null,则其指向节点的全部key小于v(keyi+1)v(keyi+1)且大于v(keyi)v(keyi)。
图2是一个d=2的B-Tree示意图。
图2
因为B-Tree的特性,在B-Tree中按key检索数据的算法很是直观:首先从根节点进行二分查找,若是找到则返回对应节点的data,不然对相应区间的指针指向的节点递归进行查找,直到找到节点或找到null指针,前者查找成功,后者查找失败。B-Tree上查找算法的伪代码以下:
关于B-Tree有一系列有趣的性质,例如一个度为d的B-Tree,设其索引N个key,则其树高h的上限为logd((N+1)/2)logd((N+1)/2),检索一个key,其查找节点个数的渐进复杂度为O(logdN)O(logdN)。从这点能够看出,B-Tree是一个很是有效率的索引数据结构。
另外,因为插入删除新的数据记录会破坏B-Tree的性质,所以在插入删除时,须要对树进行一个分裂、合并、转移等操做以保持B-Tree性质,本文不打算完整讨论B-Tree这些内容,由于已经有许多资料详细说明了B-Tree的数学性质及插入删除算法,有兴趣的朋友能够在本文末的参考文献一栏找到相应的资料进行阅读。
B-Tree有许多变种,其中最多见的是B+Tree,例如MySQL就广泛使用B+Tree实现其索引结构。
与B-Tree相比,B+Tree有如下不一样点:
每一个节点的指针上限为2d而不是2d+1。
内节点不存储data,只存储key;叶子节点不存储指针。
图3是一个简单的B+Tree示意。
图3
因为并非全部节点都具备相同的域,所以B+Tree中叶节点和内节点通常大小不一样。这点与B-Tree不一样,虽然B-Tree中不一样节点存放的key和指针可能数量不一致,可是每一个节点的域和上限是一致的,因此在实现中B-Tree每每对每一个节点申请同等大小的空间。
通常来讲,B+Tree比B-Tree更适合实现外存储索引结构,具体缘由与外存储器原理及计算机存取原理有关,将在下面讨论。
通常在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增长了顺序访问指针。
图4
如图4所示,在B+Tree的每一个叶子节点增长一个指向相邻叶子节点的指针,就造成了带有顺序访问指针的B+Tree。作这个优化的目的是为了提升区间访问的性能,例如图4中若是要查询key为从18到49的全部数据记录,当找到18后,只需顺着节点和指针顺序遍历就能够一次性访问到全部数据节点,极大提到了区间查询效率。
这一节对B-Tree和B+Tree进行了一个简单的介绍,下一节结合存储器存取原理介绍为何目前B+Tree是数据库系统实现索引的首选数据结构。
上文说过,红黑树等数据结构也能够用来实现索引,可是文件系统及数据库系统广泛采用B-/+Tree做为索引结构,这一节将结合计算机组成原理相关知识讨论B-/+Tree做为索引的理论基础。
通常来讲,索引自己也很大,不可能所有存储在内存中,所以索引每每以索引文件的形式存储的磁盘上。这样的话,索引查找过程当中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,因此评价一个数据结构做为索引的优劣最重要的指标就是在查找过程当中磁盘I/O操做次数的渐进复杂度。换句话说,索引的结构组织要尽可能减小查找过程当中磁盘I/O的存取次数。下面先介绍内存和磁盘存取原理,而后再结合这些原理分析B-/+Tree做为索引的效率。
磁盘中有两个机械运动的部分,分别是盘片旋转和磁臂移动。盘片旋转就是咱们市面上所提到的多少转每分钟,而磁盘移动则是在盘片旋转到指定位置之后,移动磁臂后开始进行数据的读写。那么这就存在一个定位到磁盘中的块的过程,而定位是磁盘的存取中花费时间比较大的一块,毕竟机械运动花费的时候要远远大于电子运动的时间。当大规模数据存储到磁盘中的时候,显然定位是一个很是花费时间的过程,可是咱们能够经过B树进行优化,提升磁盘读取时定位的效率。
为何B类树能够进行优化呢?咱们能够根据B类树的特色,构造一个多阶的B类树,而后在尽可能多的在结点上存储相关的信息,保证层数尽可能的少,以便后面咱们能够更快的找到信息,磁盘的I/O操做也少一些,并且B类树是平衡树,每一个结点到叶子结点的高度都是相同,这也保证了每一个查询是稳定的。
这里的B树,也就是英文中的B-Tree,一个 m 阶的B树知足如下条件:
举个栗子:
B树上大部分的操做所须要的磁盘存取次数和B树的高度是成正比的,在B树中能够检查多个子结点,因为在一棵树中检查任意一个结点都须要一次磁盘访问,因此B树避免了大量的磁盘访问。
既然是树,那么必不可少的操做就是插入和删除,这也是B树和其它数据结构不一样的地方,固然了,还有必不可少的搜索,分享一个对B树的操做进行可视化的网址,它是由usfca提供的。
假定对高度为h的m阶B树进行操做。
新结点通常插在第h层,经过搜索找到对应的结点进行插入,那么根据即将插入的结点的数量又分为下面几种状况。
其过程以下:
一样的,咱们须要先经过搜索找到相应的值,存在则进行删除,须要考虑删除之后的状况,
若是该结点在删除关键字之后不知足B树的性质(关键字没有到达ceil(m/2)-1的数量),则须要向兄弟结点借关键字,这有分为兄弟结点的关键字数量是否足够的状况。
其过程以下:
因为B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只须要扫一遍叶子结点便可,可是B树由于其分支结点一样存储着数据,咱们要找到具体的数据,须要进行一次中序遍历按序来扫,因此B+树更加适合在区间查询的状况,因此一般B+树用于数据库索引,而B树则经常使用于文件索引。
一样的,以一个m阶树为例:
其操做和B树的操做是相似的,不过须要注意的是,在增长值的时候,若是存在满员的状况,将选择结点中的值做为新的索引,还有在删除值的时候,索引中的关键字并不会删除,也不会存在父亲结点的关键字下沉的状况,由于那只是索引。
这都是因为B+树和B具备这不一样的存储结构所形成的区别,以一个m阶树为例。
目前计算机使用的主存基本都是随机读写存储器(RAM),现代RAM的结构和存取原理比较复杂,这里本文抛却具体差异,抽象出一个十分简单的存取模型来讲明RAM的工做原理。
图5
从抽象角度看,主存是一系列的存储单元组成的矩阵,每一个存储单元存储固定大小的数据。每一个存储单元有惟一的地址,现代主存的编址规则比较复杂,这里将其简化成一个二维地址:经过一个行地址和一个列地址能够惟必定位到一个存储单元。图5展现了一个4 x 4的主存模型。
主存的存取过程以下:
当系统须要读取主存时,则将地址信号放到地址总线上传给主存,主存读到地址信号后,解析信号并定位到指定存储单元,而后将此存储单元数据放到数据总线上,供其它部件读取。
写主存的过程相似,系统将要写入单元地址和数据分别放在地址总线和数据总线上,主存读取两个总线的内容,作相应的写操做。
这里能够看出,主存存取的时间仅与存取次数呈线性关系,由于不存在机械操做,两次存取的数据的“距离”不会对时间有任何影响,例如,先取A0再取A1和先取A0再取D3的时间消耗是同样的。
上文说过,索引通常以文件形式存储在磁盘上,索引检索须要磁盘I/O操做。与主存不一样,磁盘I/O存在机械运动耗费,所以磁盘I/O的时间消耗是巨大的。
图6是磁盘的总体结构示意图。
图6
一个磁盘由大小相同且同轴的圆形盘片组成,磁盘能够转动(各个磁盘必须同步转动)。在磁盘的一侧有磁头支架,磁头支架固定了一组磁头,每一个磁头负责存取一个磁盘的内容。磁头不能转动,可是能够沿磁盘半径方向运动(实际是斜切向运动),每一个磁头同一时刻也必须是同轴的,即从正上方向下看,全部磁头任什么时候候都是重叠的(不过目前已经有多磁头独立技术,可不受此限制)。
图7是磁盘结构的示意图。
图7
盘片被划分红一系列同心环,圆心是盘片中心,每一个同心环叫作一个磁道,全部半径相同的磁道组成一个柱面。磁道被沿半径线划分红一个个小的段,每一个段叫作一个扇区,每一个扇区是磁盘的最小存储单元。为了简单起见,咱们下面假设磁盘只有一个盘片和一个磁头。
当须要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即肯定要读的数据在哪一个磁道,哪一个扇区。为了读取这个扇区的数据,须要将磁头放到这个扇区上方,为了实现这一点,磁头须要移动对准相应磁道,这个过程叫作寻道,所耗费时间叫作寻道时间,而后磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫作旋转时间。
因为存储介质的特性,磁盘自己存取就比主存慢不少,再加上机械运动耗费,磁盘的存取速度每每是主存的几百分分之一,所以为了提升效率,要尽可能减小磁盘I/O。为了达到这个目的,磁盘每每不是严格按需读取,而是每次都会预读,即便只须要一个字节,磁盘也会从这个位置开始,顺序向后读取必定长度的数据放入内存。这样作的理论依据是计算机科学中著名的局部性原理:
当一个数据被用到时,其附近的数据也一般会立刻被使用。
程序运行期间所须要的数据一般比较集中。
因为磁盘顺序读取的效率很高(不须要寻道时间,只需不多的旋转时间),所以对于具备局部性的程序来讲,预读能够提升I/O效率。
预读的长度通常为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操做系统每每将主存和磁盘存储区分割为连续的大小相等的块,每一个存储块称为一页(在许多操做系统中,页得大小一般为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,而后异常返回,程序继续运行。
到这里终于能够分析B-/+Tree索引的性能了。
上文说过通常使用磁盘I/O次数评价索引结构的优劣。先从B-Tree分析,根据B-Tree的定义,可知检索一次最多须要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每一个节点只须要一次I/O就能够彻底载入。为了达到这个目的,在实际实现B-Tree还须要使用以下技巧:
每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
B-Tree中一次检索最多须要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)O(h)=O(logdN)。通常实际应用中,出度d是很是大的数字,一般超过100,所以h很是小(一般不超过3)。
综上所述,用B-Tree做为索引结构效率是很是高的。
而红黑树这种结构,h明显要深的多。因为逻辑上很近的节点(父子)物理上可能很远,没法利用局部性,因此红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差不少。
上文还说过,B+Tree更适合外存索引,缘由和内节点出度d有关。从上面分析能够看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:
dmax=floor(pagesize/(keysize+datasize+pointsize))dmax=floor(pagesize/(keysize+datasize+pointsize))
floor表示向下取整。因为B+Tree内节点去掉了data域,所以能够拥有更大的出度,拥有更好的性能。
这一章从理论角度讨论了与索引相关的数据结构与算法问题,下一章将讨论B+Tree是如何具体实现为MySQL中索引,同时将结合MyISAM和InnDB存储引擎介绍非汇集索引和汇集索引两种不一样的索引实现形式。
在MySQL中,索引属于存储引擎级别的概念,不一样存储引擎对索引的实现方式是不一样的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。
MyISAM引擎使用B+Tree做为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:
图8
这里设表一共有三列,假设咱们以Col1为主键,则图8是一个MyISAM表的主索引(Primary key)示意。能够看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是惟一的,而辅助索引的key能够重复。若是咱们在Col2上创建一个辅助索引,则此索引的结构以下图所示:
图9
一样也是一颗B+Tree,data域保存数据记录的地址。所以,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,则取出其data域的值,而后以data域的值为地址,读取相应数据记录。
MyISAM的索引方式也叫作“非汇集”的,之因此这么称呼是为了与InnoDB的汇集索引区分。
虽然InnoDB也使用B+Tree做为索引结构,但具体实现方式却与MyISAM大相径庭。
第一个重大区别是InnoDB的数据文件自己就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件自己就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引。
图10
图10是InnoDB主索引(同时也是数据文件)的示意图,能够看到叶节点包含了完整的数据记录。这种索引叫作汇集索引。由于InnoDB的数据文件自己要按主键汇集,因此InnoDB要求表必须有主键(MyISAM能够没有),若是没有显式指定,则MySQL系统会自动选择一个能够惟一标识数据记录的列做为主键,若是不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整形。
第二个与MyISAM索引的不一样是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的全部辅助索引都引用主键做为data域。例如,图11为定义在Col3上的一个辅助索引:
图11
这里以英文字符的ASCII码做为比较准则。汇集索引这种实现方式使得按主键的搜索十分高效,可是辅助索引搜索须要检索两遍索引:首先检索辅助索引得到主键,而后用主键到主索引中检索得到记录。
了解不一样存储引擎的索引实现方式对于正确使用和优化索引都很是有帮助,例如知道了InnoDB的索引实现后,就很容易明白为何不建议使用过长的字段做为主键,由于全部辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段做为主键在InnoDB中不是个好主意,由于InnoDB数据文件自己是一颗B+Tree,非单调的主键会形成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段做为主键则是一个很好的选择。
下一章将具体讨论这些与索引有关的优化策略。
B-/+Tree索引的性能优点: 通常使用磁盘I/O次数评价索引优劣。
1.结合操做系统存储结构优化处理: mysql巧妙运用操做系统存储结构(一个节点分配到一个存储页中->尽可能减小IO次数) & 磁盘预读(缓存预读->加速预读立刻要用到的数据).
2.B+Tree 单个节点能放多个子节点,相同IO次数,检索出更多信息。
3.B+TREE 只在叶子节点存储数据 & 全部叶子结点包含一个链指针 & 其余内层非叶子节点只存储索引数据。只利用索引快速定位数据索引范围,先定位索引再经过索引高效快速定位数据。
详解:Mysql设计利用了磁盘预读原理,将一个B+Tree节点大小设为一个页大小,在新建节点时直接申请一个页的空间,这样就能保证一个节点物理上存储在一个页里,加之计算机存储分配都是按页对齐的,这样就实现了每一个Node节点只须要一次I/O操做。
B-Tree索引、B+Tree索引: 单个节点能放多个子节点,查询IO次数相同(mysql查询IO次数最多3-5次-因此须要每一个节点须要存储不少数据)
B+TREE 只在叶子节点存储数据 & 全部叶子结点包含一个链指针 & 其余内层非叶子节点只存储索引数据。只利用索引快速定位数据索引范围,先定位索引再经过索引高效快速定位数据。
B+Tree更适合外存索引,缘由和内节点出度d有关。从上面分析能够看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:
B+Tree内节点去掉了data域,所以能够拥有更大的出度,拥有更好的性能。只利用索引快速定位数据索引范围,先定位索引再经过索引高效快速定位数据。
dmax=floor(pagesize/(keysize+datasize+pointsize))
聚簇索引: 索引 和 数据文件为同一个文件。非聚簇索引: 索引 和 数据文件分开的索引。
MyISAM & InnoDB 都使用B+Tree索引结构。可是底层索引存储不一样,MyISAM 采用非聚簇索引,而InnoDB采用聚簇索引。
MyISAM索引原理:采用非聚簇索引-MyISAM myi索引文件和myd数据文件分离,索引文件仅保存数据记录的指针地址。叶子节点data域存储指向数据记录的指针地址。(底层存储结构: frm -表定义、 myi -myisam索引、 myd-myisam数据)
MyISAM索引按照B+Tree搜索,若是指定的Key存在,则取出其data域的值,而后以data域值-数据指针地址去读取相应数据记录。辅助索引和主索引在结构上没有任何区别,只是主索引要求key是惟一的,而辅助索引的key能够重复。MyISAM索引树以下:
InnoDB优点:高扩展性,充分发挥硬件性能、 Crash Safe、 支持事务、 能够在线热备份
InnoDB特性:
1. 事务支持(ACID)2. 扩展性优良 3. 读写不冲突 4. 缓存加速
2. 功能组件: redo/undo & 异步IO & MVCC & 行级别锁 & Page Cache(LRU)
InnoDB物理存储结构以下图:
InnoDB表空间管理
InnoDB物理存储文件结构说明:
InnoDB以表空间Tablespace(idb文件)结构进行组织,每一个Tablespace 包含多个Segment段,每一个段(分为2种段:叶子节点Segment&非叶子节点Segment), 一个Segment段包含多个Extent,一个Extent占用1M空间包含64个Page(每一个Page 16k),InnoDB B-Tree 一个逻辑节点就分配一个物理Page,一个节点一次IO操做。,一个Page里包含不少有序数据Row行数据,Row行数据中包含Filed属性数据等信息。
• 表空间(ibd文件)
• 段(一个索引2段:叶子节点Segment & 非叶子节点Segment)
• Extent(1MB):一个Extent(1M) 包含64个 Page(16k),一个Page里包含不少有序行数据 , InnoDB B-Tree 一个逻辑节点就分配一个物理Page,一个节点一次IO操做。
• Page(16KB)
• Row
• Field
表插入数据扩展原理: 一次扩张一个Extent空间(1M),64个Page,按照顺序结构向每一个page中插入顺序。
InnoDB逻辑组织结构:
InnoDB索引树结构
每一个索引一个B+树, 一个B+树节点 = 一个物理Page(16K)
• 数据按16KB切片为Page 并编号, 编号可映射到物理文件偏移(16K * N), B+树叶子节点先后造成双向链表, 数据按主键索引聚簇, 二级索引叶节点存储主键值, 经过叶节点主键值回表查找数据。
采用聚簇索引- InnoDB数据&索引文件为一个idb文件,表数据文件自己就是主索引,相邻的索引临近存储。 叶节点data域保存了完整的数据记录(数据[除主键id外其余列data]+主索引[索引key:表主键id])。 叶子节点直接存储数据记录,以主键id为key,叶子节点中直接存储数据记录。(底层存储结构: frm -表定义、 ibd: innoDB数据&索引文件)
注:因为InnoDB采用聚簇索引结构存储,索引InnoDB的数据文件须要按照主键汇集,所以InnoDB要求表必须有主键(MyISAM能够没有)。若是没有指定mysql会自动选择一个能够惟一表示数据记录的列做为主键,若是不存在这样的列,mysql自动为InnoDB表生成一个隐含字段(6个字节长整型)做为主键。 InnoDB的全部 辅助索引 都引用 数据记录的主键 做为data域。
聚簇索引这种实现方式使得按主键的搜索十分高效,可是辅助索引搜索须要检索两遍索引:首先检索辅助索引得到数据记录主键,而后用主键到主索引中检索得到数据记录。InnoDB聚簇索引结构:
索引查找流程:
, 顺序扫描全部结果, 直到终止条件知足id >=22 (select * from user_info where id >= 18 and id < 22)
(select * from user_info where name = 'abc')
Create table table_x(int id primary key, varchar(64) name,key sec_index(name) )
• Select * from table_x where name = “d”;
经过二级索引查出对应主键,拿主键回表查主键索引获得数据, 二级索引可筛选掉大量无效记录,提升效率