「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
Access Methods
DBMS访问表中数据的方法(scan算子)。这里介绍三种方法:顺序扫描,按索引扫描,多索引扫描(也叫bitmap scan)。
Sequential Scan
顺序遍历表的每一个page中的每一个tuple。根据谓词判断是否需要这个tuple。访问每个page的时候,首先检索buffer pool中是否有缓存。DBMS需要维护一个指针(cursor)来标记当前访问到的page/slot。
几乎是最差效率的读取方式。
一些优化方式:
- prefetching:提前加载后续的pages,避免IO阻塞
- Parallelization:并行执行scan操作
- buffer pool bypass: 将page存储在本地内存而非缓冲池中,避免sequential flooding
- zone map: 预计算每个page的一些聚集计算结果,来粗粒度的判断这个page中是否可能包含所需的数据:
- late materialization: 每个操作符只将最小的信息传递到下一个(例如record id)。只有列存储系统中有效。
- heap clustering:
Index Scan
选择一个索引来查找数据。选择索引的依据:
- 索引包含的属性
- query需要的属性
- 属性的值域
- 谓词组合
- 索引是否包含non-unique keys
multi-index scan (bitmap scan)
可以用到多个索引的query,流程一般就是如下两步:
- 从每个匹配的index中查找id set
- 根据谓词要求对这些set求union或intersect
(在Postgres中叫做bitmap scan)
计算交集,可以使用bitmap,哈希表,布隆过滤器等方法。
很显然的,我们期望尽可能的命中索引,通过索引来进行数据的检索。
index scan page sorting
由于从非聚簇索引(只能检索到tuple存储的位置,不能直接获得数据)中检索到的tuples所分布的pages是混乱的,所以可以先对这些tuples根据它们所属的pages进行排序:
总结
这一节一开始给我唬住了,看完才发现其实就是在讲索引的作用,可能这点平时会熟悉一点,所以很多觉得都是理所应当的不值得专门拎出来说。建立索引当然好,我们期望查询语句尽可能的命中索引,所以一般来说主键是一定要建立索引的,其他的属性上就要看管理员自己的考量了。索引当然也不是越多越好,因为索引越多意味着当表中的数据发生变动的时候,它所需要的维护成本越高。trade-off是一个时刻存在的概念,“均衡,存乎万物之间”。
Expression Evaluation
如上所述,SQL语句会被解析成一棵树:操作符是中间节点,操作数是叶子节点。
构建出表达式树后再进行谓词评估是很慢的,因为DBMS必须遍历树中的节点,并对每个节点要做的事情进行考量。
所以有时候直接判断表达式本身是更好的选择。
JIT
just-in time,在程序启动后,随着程序的运行来逐步进行代码编译(on the fly)。与之对比,传统的编译器会将所有的代码都转化成机器语言,之后才运行程序。