数据库算子是什么意思?

摘要:回表 1. 为什么会发生回表? 想象你在图书馆查书: 索引(Index):就像图书馆的索引卡片。卡片上写着:书名《数据库原理》,存放位置:3排-B架-12号。 表(TableHeap):就像书架上的实物书。书里才有具体的内容(作者、出版社
回表 1. 为什么会发生回表? 想象你在图书馆查书: 索引(Index):就像图书馆的索引卡片。卡片上写着:书名《数据库原理》,存放位置:3排-B架-12号。 表(Table/Heap):就像书架上的实物书。书里才有具体的内容(作者、出版社、正文)。 如果你只想知道书名,看卡片(索引)就够了。但如果你想看“作者是谁”或者“具体内容”,你就必须拿着卡片上的位置,走到书架前把那本书抽出来翻开。这个“从索引到书架取书”的过程,就是回表。 2. 回表的过程(以 PostgreSQL/MySQL 为例) 假设你有一张表 users,在 username 字段上有索引: -- 查询语句 SELECT id, username, age FROM users WHERE username = 'a'; 第一步:查索引。 数据库在 username 索引树中快速定位到 'a'。 第二步:拿指针。 索引节点里存储着该行数据的物理地址(在 MySQL 中是主键 ID,在 PostgreSQL 中是 CTID/TID)。 第三步:回表。 索引里没有 age 字段。数据库根据物理地址,回到原始数据表(Heap)中找到这一行,把 age 的值读出来。 3. 回表有什么代价? 回表是数据库性能优化的头号公敌,主要原因有两个: 随机 I/O 增加:索引通常是顺序排列的,但数据行在磁盘上的分布是零散的。每回表一次,可能都要进行一次磁盘随机读,这比顺序读慢得多。 性能损耗:如果查询结果有 10,000 行,数据库就要执行 10,000 次“回表”动作。 4. 如何避免回表? 最有效的方案是:覆盖索引(Covering Index)。 如果你经常需要根据 username 查 age,你可以建立一个包含这两个字段的索引: -- PostgreSQL 语法 CREATE INDEX idx_user_age ON users(username) INCLUDE (age); -- 或者通用的复合索引 CREATE INDEX idx_user_age_composite ON users(username, age); 发生了什么变化? 现在,age 字段的信息直接存在了索引树里。数据库查到 username 时,顺手就能把旁边的 age 带走,再也不用去翻原始表了。这种算子在执行计划中会显示为 Index Only Scan。 5. 什么时候“回表”比“不回表”还快? 并不是所有时候都要避免回表。 如果你的 WHERE 条件过滤后,只剩下几行数据,回表的代价微乎其微。 如果表很小,数据库可能会直接放弃索引,选择 Seq Scan(全表扫描)。因为它觉得“与其先看卡片再翻书,不如直接把这本薄书从头到尾翻一遍”。 总结 回表 = 在索引里没找全,得回原表取。 后果 = 产生随机 I/O,变慢。 对策 = 覆盖索引(把查的字段都塞进索引里)。 算子 在 PostgreSQL 中,算子(Operators/Nodes)是构成执行计划的最小单元。为了方便记忆,我们可以按照它们在数据处理流中的功能角色,将其分为四大类:数据扫描、连接查询、集合/聚合操作、以及辅助控制算子。 1. 数据扫描算子 (Scan Nodes) 这类算子负责从物理存储(磁盘或内存缓冲区)中读取原始数据。 算子名称 英文名 功能描述 全表扫描 Seq Scan 顺序读取整个表的所有数据页。 索引扫描 Index Scan 先扫描索引找到位置,再回表读取数据行。 索引覆盖扫描 Index Only Scan 仅通过索引就能拿到所有所需字段,无需回表。 位图扫描 Bitmap Heap/Index Scan 先在内存中构建位图标记匹配行,再批量回表,减少随机 IO。 TID 扫描 Tid Scan 通过行标识符(Tuple ID)直接定位数据。 在 PostgreSQL 中,扫描算子(Scan Nodes)是执行计划的“地基”。所有数据的处理都始于扫描,它的效率直接决定了查询的生死。 PostgreSQL 会根据数据量的大小、过滤条件的筛选率以及索引的分布,从以下几种主要扫描方式中选择最优解。 1. 全表扫描 (Seq Scan) 这是最原始的扫描方式。 工作原理: 数据库从磁盘上顺序读取该表的所有数据页(Blocks),并对每一行进行条件检查。 适用场景: 表非常小(加载索引的代价反而比全表扫描高)。 查询条件没有索引。 返回的数据占全表比例很高(例如超过 20%-30%),此时顺序 IO 比频繁的随机 IO 更快。 EXPLAIN 标志: Seq Scan on table_name。
阅读全文