转载于: https://www.ywnds.com/?p=7702

一、堆表和索引组织表

NOTE

堆表也可以称之为 HOT,索引组织表也可以称之为 IOT,下面没有特别说明,两者都是一个意思。

堆(heap)组织表数据行在堆中存储,没有任何特定顺序,向一个全新的没有做过更新和删除的堆中插入一行时候,总是 append 到堆表文件的最后一页当中。因为不用考虑排序,所以插入速度会比较快。

但是要查找符合某个条件的记录,就必须得读取全部的记录以便筛选。而这个时候为了加快查询速度,索引就出现了,索引是针对少量特定字段的值拿出来进行排序存储,存储索引 key 以及数据行在堆表上面的绝对位置(页号,页内偏移),而因为索引是有序的,所以就会很容易通过索引查询到具体的记录位置(普遍使用二分查找法),然后再根据记录位置直接从表中读取该记录。同时因为索引的字段较少,所以索引通常会比其基表小得多。

从上面通过索引访问表记录的方式可以看出,当要访问的数据量较大时,通过每一条记录的位置去访问原始记录,每一条符合条件的记录都需要经过索引访问后再访问基表这样一个复杂的过程,这会花费很多时间。同样,如果不经过索引而直接查询表,也可能因为表字段太多,记录较大的情况下把全部的数据读取进来,这也会花费很多时间。

那怎么办呢?这个时候就会想到,如果表中数据本身就是有序的,这样查询表的时候就可以快速的找到符合条件的记录位置,而很容易判断符合条件记录的位置,这样只需要读取一小部分数据出来就可以了,不需要全表记录都读取出来进行判断。索引组织表就这样产生了,当然索引表中插入,更新的时候可能会因为需要排序而将数据重组,这时候数据插入或更新速度会比堆组织表慢一些。如果堆组织表上有索引,那么对堆组织表的插入也会因为要修改索引而变慢。

二、堆表和索引组织表的比较

所以,堆表的特点就是索引和数据分开,所有索引都是二级索引,或叫辅助索引。所以主键索引也是二级索引,没有完整记录,区别只有唯一或非唯一。索引中存储的是 key 与指针,指针指向具体数据记录。当然,查找 key 的算法都是一样的,使用二分查找,也叫书签查找。

跟索引组织表相比,堆表有什么好处呢?其实主要就是通过主键或二级索引查询,开销是一样的。都是通过先找到key,然后定位到数据。而索引组织表,由于二级索引是指向主键,所以查询二级索引需要先定位到 key,然后拿到主键 id,还要根据主键 id 再次通过二分查找定位到真正的数据页。当然,索引组织表通过主键查询开销与堆是一样的。从索引组织表的工作方式可以看出,索引组织表必须要有主键,如果非显式创建,InnoDB 存储引擎会默认创建一个 ROWID 当做主键;而堆表则无强制要求。

这就是经常有文章说 MyISAM 比 InnoDB 快的原因吧,但这个说法并不完全正确,索引组织表由于索引项和数据存储在一起,且 InnoDB 聚集索引各个叶子节点之间都是同过双向链表组织,且都是根据主键逻辑顺序存放,所以无论是基于主键的等值查询还是范围查询都能大大节省磁盘访问时间。特别对于范围查询,只需要定位到开始 key 的位置,就可以顺着这个位置扫描到结束key即可。如下 SQL 语句:

 
1
select * from table where id between 1000 and 2000

根据主键查时,假设主键 b+tree 高度是 3,每个叶子节点能存储 100 条记录,1000 条记录需要 10 个页。那么这个查询只需要大概 2 + 9 次 io 开销。

另外由于索引组织表的特性带来另外一个优点,举例来说,假设表 tab1(a int primary key, b int) 有两行 R1(1,2) 和 R2(2,3),那么如果 tab1 的主键索引是聚簇的 — 例如 InnoDB 就是这样 — 那么 R1 和 R2 由于其主键值是相邻的,所以在磁盘上面它们也是相邻存放的。也就是说 R1 和 R2 大概率在同一个磁盘页面上面(也可能是 R1 刚好位于一个 leaf page 的最后一行,而 R2 刚好是下一个 leaf page 的第一行,在这种情况下,我们仍然说 R1 和 R2 是相邻的),这样一次逻辑 io 查询的数据行命中率可能是 90%。

而堆表的索引只存储索引 key 以及数据行在堆表上面的绝对位置(页号,页内偏移),这样,主键值相邻的两行,它们在堆表的数据行经常位于不同的页面,除非这个表很少更新删除,并且插入的时候是按照主键值递增的顺序做 ‘append’ 型的插入的,不会后续在 pk 的已存在范围做插入。大多数 OLTP 类应用的逻辑无法满足这样苛刻的要求。这样,如果数据和查询具有局部性(通常如此),那么就无法享受到聚集索引带来的性能优势。

当然了,有序的代价也是很大的,无法 ‘append’ 插入,涉及数据重组,也就是索引页分裂与均衡。另外,如果对于索引组织表范围查询走的是二级索引,那么开销是多大呢?

如下 SQL 语句,同样是查询二级索引 1000 条记录。

 
1
select * from table where date >= 1990 limit 1000

这里假设二级索引 b+tree 高度也是 3,假设每个页子节点能存储200条键值对,这里的开销就变成了 3 + 4 + 3000 次 IO 开销了(其中3是定位到开始值的数据页,4 是扫描二级索引 1000 条数据需要扫描的页,3000 = 3*1000 表示回表到主键 1000 次产生的 IO)。这种方式也称之为回表,从二级索引回到主键。所以在这种情况下,InnoDB 很多时候都选择了直接扫描主键,也就是全表扫描,其代价可能比回表开销更小,比如在表数据页小于回表所产生的 io 次数时,因为全表扫描每个页也就一次 io 而已。这在 MySQL 5.6 之前都是这么工作的,但在 MySQL 5.6 有了 MRR 技术后,这种情况就改善了很多。

MRR 简单来说就是为每个线程开辟了一块内存空间,由 read_rnd_buffer_size 参数设置,默认 32M,把二级索引查询结果放到这块空间,并且做排序,然后利用排序后的数据进行回表,就是顺序的了。如果 mrr 内存够大,那么最快可以一次回表就拿到所有数据。当然mrr优化主要是针对磁盘的,磁盘越慢效果越好。如果你的 buffer pool 可以装下所有表数据,那么 MRR 效果其实也不大了,但一般这种情况很少。

那么堆表的缺点是什么呢?

这里我们想一下,由于堆表的索引只存储索引 key 以及数据行在堆表上面的绝对位置(页号,页内偏移),如果这行记录发生了更新,并且不能原地更新,需要进行迁移,那么就会发生一个情况,堆表所有索引都需要修改,指向新的行位置。而索引组织表就不需要这个开销,更新只会新插入变化了的索引 key,不变的索引 key 不需要新插入,只有当主键发生更改才需要对应修改其他二级索引,通常主键也不会更新,所以这也就是索引组织表更新效率更高的由来。

但一般使用堆表的数据库都不会直接这么更新,代价太大了。而是会在数据页预留一些空间,当遇见不能原地更新的记录时,就会在这个页中新插入一条更新后的记录,然后在这个页中做一个指针把老记录指向新纪录,这样就不用更新索引信息了。当然,如果你这个页中没有空闲空间可以插入新的记录,那么还是需要做行迁移,然后更新所有索引。

[转帖]堆表(HOT)和索引组织表(IOT)优缺点的更多相关文章

  1. Oracle数据库 查看表是否是 索引组织表的方法

    1. 最近在工作过程中发现 一个表插入很慢 以为是索引组织表, 所以一直有点纠结 但是发现 产品里面是没有IOT的 于是找了下公司的OCP 问了下 如何查看 就是 user_tables 视图里面的一 ...

  2. 聚集索引、非聚集索引、聚集索引组织表、堆组织表、Mysql/PostgreSQL对比、联合主键/自增长、InnoDB/MyISAM(引擎方面另开一篇)

    参考了多篇文章,分别记录,如下. 下面是第一篇的总结 http://www.jb51.net/article/76007.htm: 在MySQL中,InnoDB引擎表是(聚集)索引组织表(cluste ...

  3. MySQL InnoDB 索引组织表 & 主键作用

    InnoDB 索引组织表 一.索引组织表定义 在InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表(index organized table IOT). 在Inno ...

  4. 4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志

    跟踪标记:610 功能: 用批量导入操作(Bulk Import Operations)加载数据时,对于索引组织表(即有聚集索引的表) 最小化日志: 上图为simple/bulk-logged恢复模式 ...

  5. mysql之索引组织表

    1.二叉树/平衡树.B-tree.B+tree.B*tree 树:最上一层是根节点.最底下一层是叶子节点.(一般左边节点小于右边节点) 二叉树:每个节点最多只能有两个分支,一般只用于教材.二叉树的深度 ...

  6. 查找->静态查找表->分块查找(索引顺序表)

    文字描述 分块查找又称为索引顺序查找,是顺序查找的一种改进方法.在此查找算法中,除表本身外, 还需要建立一个”索引表”.索引表中包括两项内容:关键字项(其值为该字表内的最大关键字)和指针项(指示该子表 ...

  7. 查看Oracle当前用户下的信息(用户,表视图,索引,表空间,同义词,存储过程函数,约束条件)

    0.表空间 SQL>select username,default_tablespace from user_users; 查看当前用户的角色 SQL>select * from user ...

  8. 7、SQL Server索引、表压缩

    索引 什么是索引? 索引是一种磁盘上的数据结构,建立在表或视图的基础上.使用索引可以使数据的获取更快更高校,也会影响其他的一些性能,如插入或更新等. 索引主要分为两种类型:聚集索引和非聚集索引. 字典 ...

  9. Oracle大表改为分区表及表空间切换方案

    Oracle大表改为分区表及表空间切换方案 一.            背景 由于之前数据库表和索引放在一个表空间导致表空间数据文件增长太快,文件数量即将达到Oracle表空间的限制,需要对表(没有分 ...

  10. Mysql索引的类型和优缺点

    索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针.注:[1]索引不是万能的!索引可以加快数据检索操作,但会使数据修改操作变慢.每修改数据 ...

随机推荐

  1. Supershell防溯源反制配置

    简介 项目地址:https://github.com/tdragon6/Supershell Supershell是一个集成了reverse_ssh服务的WEB管理平台,使用docker一键部署(快速 ...

  2. 9 个让你的 Python 代码更快的小技巧

    哈喽大家好,我是咸鱼 我们经常听到 "Python 太慢了","Python 性能不行"这样的观点.但是,只要掌握一些编程技巧,就能大幅提升 Python 的运 ...

  3. MyBatis中使用#{}和${}占位符传递参数的各种报错信息处理

    在Mapper层使@Select注解进行SQL语句查询时,往往需要进行参数传入和拼接,一般情况下使用两种占位符#{参数名}和${参数名},两者的区别为: 一.两种占位符的区别 1.参数传入方式的区别 ...

  4. 2023-08-18:用go写算法。你会得到一个字符串 text, 你应该把它分成 k 个子字符串 (subtext1, subtext2,…, subtextk)。 要求满足: subtexti 是

    2023-08-18:用go写算法.你会得到一个字符串 text, 你应该把它分成 k 个子字符串 (subtext1, subtext2,-, subtextk). 要求满足: subtexti 是 ...

  5. Flink实时处理入门

    Flink实时处理入门 1.Flink框架介绍 Flink 诞生于欧洲的一个大数据研究项目 StratoSphere.它是由 3 所地处柏林的大学和欧洲其他一 些大学在 2010~2014 年共同进行 ...

  6. EDS从小白到专家丨打造数据交换的六边形卫士,让你的数据你做主

    本文分享自华为云社区<[EDS从小白到专家]第4期:打造数据交换的六边形卫士,让你的数据你做主>,作者: 开天aPaaS小助手 . 你还在担心数据共享后一旦"失控"将爆 ...

  7. 带你掌握不同平台下,探索JDK源码所需的native方法

    摘要:要探索JDK的核心底层源码,那必须掌握native用法.文章中会以"获取系统的默认时区"为例,介绍说明如何查看native对应方法的源码. 本文分享自华为云社区<要探索 ...

  8. 列存Delta表是个什么东东

    摘要:本文从delta表的概念.来历.用法.开启后的影响,delta表数据转移到主表几个方面做了详细的介绍. 本文分享自华为云社区<GaussDB(DWS) 列存delta表的简单介绍>, ...

  9. 不知如何优选达人?火山引擎 VeDI 零售行业解决方案一键解决!

      技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 "人-货匹配"这句营销老话,在直播电商兴起的这几年,似乎不再专指消费者与商品之间的关系. 过去 ...

  10. 【奥运会】yahoo的这个骚操作令人费解。。。

    昨天在朋友圈发了一张截图,貌似很多朋友没有 get 到点,我也实在搞不懂 Yahoo 的这波操作. 默认排序是按照金牌总数,那必然是美国第一名了.不过习惯上不应该是按照金牌总数进行排名吗?毕竟金银铜牌 ...