在之前的博文中简单提到了索引的分类与索引的可选择性查看:Click HERE
这片博客主要包含内容:索引组织表,索引算法B+树简单介绍
索引组织表
在innodb存储引擎中,表都是根据主键顺序组织存放的,使用这种存储方式的表就叫做索引组织表(index organized table 简称IOT表)。
在innodb存储引擎中,每张表都有个主键(primary key),如果创建表是没有显式的定义主键,则INNODB存储引擎会按如下方式选择或创建主键。
- 首先判断表中是否有非空唯一索引,如果有,则该列即主键。
- 如果不符合上述条件,INNODB存储引擎会自动创建一个6字节大小的指针。
当表中有多个非空的唯一索引时,INNODB存储引擎将选择建表时第一个定义的非空唯一索引为主键。这里需要说明的是,主键的选择根据的是定义索引的顺序而不是建表时列的顺序。
CREATE TABLE t1 ( a INT NOT NULL, b INT NULL, c INT NOT NULL, d INT NOT NULL, UNIQUE KEY (b), UNIQUE KEY (d), UNIQUE KEY (c) ); insert into t1 select 1,2,3,4; insert into t1 select 5,6,7,8; insert into t1 select 9,10,11,12; #上面创建了表, 并且创建了索引,注意索引的顺序,然后插入了数据。
#使用字段_rowid可以查看表中的主键,_rowid只可以用来查看单列索引的主键。 #注意主键非空的唯一索引 mysql> select a, b, c, d, _rowid from t1; +---+------+----+----+--------+ | a | b | c | d | _rowid | +---+------+----+----+--------+ | 1 | 2 | 3 | 4 | 4 | | 5 | 6 | 7 | 8 | 8 | | 9 | 10 | 11 | 12 | 12 | +---+------+----+----+--------+ 3 rows in set (0.00 sec) mysql>
这里提到INNODB存储引擎是索引组织表?那么在INNODB的内部是如何使用主键将表组织起来的呢?
INNODB存储引擎概述
存储引擎的索引分类(安装索引的内部实现不同):
- B+树索引
- 哈希索引(INNODB是自适应哈希索引)
- 全文索引
B+树索引就是传统意义上的索引,也就是上面提到过那种类型的索引,这是目前关系型数据库系统中查找最为常用和最为有效的索引。B+树索引的构造类似于二叉树。
哈希索引,INNODB存储引擎是自适应的,INNODB存储引擎会根据表的使用情况自动为表生成哈希索引,不能认为干预是否在一张表中生成哈希索引。
全文索引,会在后面讲述。
B+树索引
B+树索引并不能找到一个给定键值的具体的行,只能找到这个记录所在的数据页。然后把这个数据页读到内存(innodb_buffer_pool_size)中,然后找到其中的记录。
一个问题:把对应的页读到内存中,那么是如何在这个页中找到对应的记录呢?
上面提到到INNODB时索引组织表,是按照主键的顺序排放的,这里按照顺序是按照逻辑顺序存放的,每个页之间通过双向链表链接。但是数据在一个物理页上却是物理有序的。也就是说,读到内存中的这个页是物理有序,这时候我们要在这个有序的队列中找到想要的记录,就会很方便了。但是这里具体是怎么查找的?INNODB使用的是二分查找法。
二分查找法:
二分查找法也称折半查找法,用来查找一组有序的记录数组中某一记录,其基本思想是:将记录按有序化排列,在查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该元素中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。
通过一个例子说明二分查找法: 一个有序数列如下: 5 10 19 21 23 25 27 31 33 寻找31这个数字: 第一次找到中间数23, 31>23, 所以第二次要在后半段查找也就是23 25 27 31 33中查找。 然后重复上面的步骤。 注意:二分查找法通过降低比较的次数,也就是降低的是cpu的使用。
#!/usr/bin/env python #*-* coding:utf -8 *-* #二分法查找数值 import sys import random def UnsortList(): ###如果没有指定参数,随机生成一个序列 list = [] long = random.randint(0,100) for i in range(long): list.append(random.randint(0,10000)) return list def BinarySearch(list, mark, low=0,uplow=None): #二分法查找 if not uplow: uplow = len(list) -1 if low == uplow: assert mark == list[uplow] return uplow else: mid = (low + uplow) // 2 if mark > list[mid]: return BinarySearch(list, mark,mid+1,uplow) else: return BinarySearch(list,mark,low,uplow=mid) def SuijiMark(list): ###在列表中随机挑选一个要查找的数据 l = len(list) mark = list[random.randint(0,l) - 1] return mark def main(): ####主函数 Ulist = [] print "1:随机产生列表,验证二分法" print "2:用户自己输入数值生成列表,验证二分法" answer = input("请输入对应的数字: ") if answer == 1: Ulist = UnsortList() mark = SuijiMark(Ulist) print "The list is %s" % Ulist print "The mark is %s" % mark print "The len of the list is %s " % len(Ulist) elif answer == 2: lang = input("请输入列表长度: ") ##根据输入的数值,组成列表 for i in range(lang): Ulist.append(input("请输入列表第%d个值:" % (i + 1))) mark = SuijiMark(Ulist) print "the list is %s" % Ulist print "the mark is %s" % mark else: print "请输入合法的数字" Ulist.sort() index = BinarySearch(Ulist, mark) print "The index %s is %s" % (index, mark) if __name__ == "__main__": main()