转载于: 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. OpenSSL命令总结

    OpenSSL命令总结 疑今者察之古,不知来者视之往. 导航 介绍 对称加密 公钥加密 信息摘要 数字证书 杂项 介绍 密码学标准和互联网协议一样,是一种大家都遵守的约定和标准,比如PKCS#1中规定 ...

  2. 扩展 jQurey.i18n.properties 的能力来向 vue-i18n 靠齐

    jQuery.i18n.properties 是 jQuery 老项目的国际化框架,其实国际化方案本质上都大同小异,都是需要用翻译函数包裹词条,然后根据词条文件来进行翻译 就是使用上与其他框架不太一样 ...

  3. Protobuf 的基本使用

    Protobuf 是 Google 用于序列化数据对象的一种机制,使得数据对象能够在应用程序和服务器之间进行交互,尽管现在 Java 已经对应的序列化的实现方式,但是传统的序列化方式存在严重的缺陷,因 ...

  4. 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 08.创建主HUD & 自定义作弊指令

    斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本篇文章对应课程Lecture 14 ,56-58节.本篇文章将会教你将之前创建的各种UMG控件统合到一个主控件 ...

  5. Programming Abstractions in C阅读笔记:p196

    <Programming Abstractions in C>学习第63天,p196总结.涉及到编程之外的知识,依然是读起来很费劲,需要了解作者在书中提到的人物(Edouard Lucas ...

  6. vue常用函数

     this.$router.back();  //回退上一页面

  7. 数据湖探索DLI新功能:基于openLooKeng的交互式分析

    摘要:基于华为开源openLooKeng引擎的交互式分析功能,将重磅发布便于用户构建轻量级流.批.交互式全场景数据湖. 在这个"信息爆炸"的时代,大数据已经成为这个时代的关键词之一 ...

  8. 【“互联网+”大赛华为云赛道】GaussDB命题攻略:支持三种开发语言,轻松完成数据库缓冲池

    摘要:七届中国国际"互联网+"大学生创新创业大赛火热报名中,为了帮助参赛者更好了解赛题设计思路和命题方向,华为云产业命题赛道举行了线上直播解读,华为云数据库资深架构师苏斌在直播间详 ...

  9. 2023 年汽车行业向好发展,火山引擎 VeDI 助力车企数智转型

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,并进入官方交流群 2023 年的汽车市场,预计能有一个向好的转型. 据中汽协公布的 2022 年 1-11 月累计汽车销量数据,达到 243 ...

  10. 还在用 Excel 和 SQL?火山引擎 VeDI 这款产品帮你更快处理数据

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,并进入官方交流群 对大多数职场打工人来说,看数据.用数据一直是项有"门槛"的工作. 特别是在企业业务快速发展的背景下,为 ...