Mysql索引(二)
#mysql一次查询,需要几次磁盘IO,一次IO影响的因素有哪些
- 存储引擎:Innodb和MyIsam;
Innodb引擎:聚集索引(聚簇索引/主键索引)和非聚集索引(非聚簇索引/二级索引/辅助索引);
聚集索引:叶子结点存储的是行数剧;
非聚集索引:叶子结点存储的是数据的主键;
- 一次查找:
聚集索引:(主键索引)从上至下遍历一次B+树,直到找到具体的主键,拿到叶子结点存储的数据。
非聚集索引:(二级索引)需要遍历两次B+树,第一次遍历是找到对应的主键,第二次遍历是根据主键找到具体的数据。
- 回表概念:
回表就是通过二级索引拿到主键id之后,要再去遍历聚集索引的B+树,这个过程就叫做回表。回表的操作更多的是随机io,随机io在性能上还是比较低下的。
- 执行一次sql的IO次数:
- 数据量小的话,直接把索引放到内存中,内存的消耗是远远低于磁盘io的,所以可以忽略不计;
- 数据量大的话,采用索引结构,B+树;
- 除了根节点之外,第二层级的数量得到了充分的扩展,相对于普通的二叉树,B+树的结构更加庞大又不失美感,假设叶节点不同元素占用情况为:左右指针各占4Byte,id值8Byte,目标记录指针4Byte,那么一个4Kb的磁盘块将大致可以容纳250个下级指针,100万行目标记录只需log250N=1000000即N=3的I/O次数,充分提升了每次节点I/O带来的检索效用,时间复杂度是O(lognN),这里的n是非叶子结点的个数。(PS:实际上innodb的数据页大小是16kb,这个n会更大,那么对应的,io次数也会更少);
- 在实际的查询中,IO次数可能会更小,因为有可能会把部分用到的索引读取到内存中,相对于磁盘IO来说,内存的io消耗可以忽略不计。一般来说B+Tree的高度一般都在2-4层,MySQL的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作(根节点的那次不算磁盘I/O);
- 磁盘IO:数据库的数据存放在磁盘上面,磁盘读取依靠的是机械运动,分为寻道时间、旋转延迟、传输时间三个部分,这三个部分耗时相加就是一次磁盘IO的时间,大概9ms左右。这个成本是访问内存的十万倍左右;正是由于磁盘IO是非常昂贵的操作,所以计算机操作系统对此做了优化:
- 预读;每一次IO时,不仅仅把当前磁盘地址的数据加载到内存,同时也把相邻数据也加载到内存缓冲区中。因为局部预读原理说明:当访问一个地址数据的时候,与其相邻的数据很快也会被访问到。每次磁盘IO读取的数据我们称之为一页(page)。一页的大小与操作系统有关,一般为4k或者8k。这也就意味着读取一页内数据的时候,实际上发生了一次磁盘IO。
因为有了磁盘IO预读机制,所以才有了减少磁盘IO的可能,因为一次磁盘IO操作,可以查找到物理存储中相邻的一大片数据。一次磁盘IO操作可以取出物理存储中相邻的一大片数据,如果查询的索引数据(就是B+树中从根节点一直到叶子节点整个过程中查询的节点数)都集中在该区域,那么只需要一次磁盘IO,否则就需要多次磁盘IO;
- 我们为了减少磁盘IO的次数,就你必须降低树的深度,将“瘦高”的树变得“矮胖”。
(1)、每个节点存储多个元素
(2)、摒弃二叉树结构,采用多叉树-----多路查找树 - mysql一次普通查询经过的步骤 从查询过程上看,大致步骤是:
- 查看缓存中是否存在id;
- 如果有 则从内存中访问,否则要访问磁盘;
- 并将索引数据存入内存,利用索引来访问数据;
- 对于数据也会检查数据是否存在于内存;
- 如果没有则访问磁盘获取数据,读入内存;
- 返回结果给用户;
-
今天的学习就到这里