【活动】第七期直播教程学习笔记分享贴

在目前的版本中,数据不均匀的情况下 OB 是会按照生成计划时的第一组参数去生成计划的。在生成计划的过程中,OB 会结合过滤条件列上的统计信息(例如 NDV 、null 的数量、最大最小值等)和存储层的估行去生成计划。当然这里生成的计划对于所有参数来说未必是最优的,如果需要得到一个相对稳定的计划需要人工介入,通过 outline 来绑定计划。或者可以给这条 SQL 加上 USE_PLAN_CACHE(NONE) 的 hint,来强制让这条 SQL 不走计划缓存,对每一个参数都走一次硬解析的流程。

第二个问题:目前没有很好的方法避免这个问题,只能通过前期测试中尽可能的找出潜在的风险点后绑定执行计划。同时在日常运维时通过 OCP 监控尽快的发现问题,并通过人工运维的方式找出有问题的 SQL 进行优化。后续 OB 会提供 SPM机制来控制执行计划的生成,防止出现计划的回退。


第三个问题: IO 消耗统计信息、返回行数等信息也是记录了的,直播的时候只介绍了 sql_audit 的部分字段,全部的字段说明可以参考开源社区文档(https://open.oceanbase.com/docs/community/oceanbase-database/V3.1.2/v-sql_audit)。目前 cpu 和 io 耗时是没有区分的,只记录了计划执行的总耗时和IO的等待时间。


第四个问题:目前慢查询日志是面向 OB 研发的一个辅助排查问题的手段,暂时没有提供分析工具。


第五个问题: 我理解这个问题里的说的传统表指的是非分区表,目前的开源版本非分区表底层是没有做分片处理的。其实无论是否分片,只要查询没有合适的索引可用都是需要全表扫描的,分片与否没有本质去表。如果开启了并行机制,那么对于非分区表在执行时会自动对整个表进行切分,多个线程会并行的扫描。


nest loop join 适合非驱动表在连接键上存在索引的场景,hash join 适合非驱动表上没有合适索引的场景。当然这个结论也不是绝对的,还是要看非驱动表需要扫描的数据量,更详细的分析可以参考一下直播回放。而 merge join 的适用场景少,主要是适用于连接两侧不需要排序,或者是 merge join 排好的序可以被后续算子使用的场景。

关于 hash join 内存使用的问题,hash join 的内存使用主要是看驱动表的大小,并且 OB 的执行引擎是提供了落盘机制的,如果消耗的内存过多是会把数据落盘的。对于 hash join,OB 会选择数据量更小的表来做驱动表,nest loop join 选择哪个表做驱动表是根据代价计算来决定的。


关于后面查询计划的问题,这位同学看来没有好好做课前预习。output 表示当前算子需要输出那些表达式。access 是 TABLE SCAN 和 SUBPLAN SCAN 独有的一个属性,在 TABLE SCAN 算子上表示表扫描需要访问表里的那些列,在 SUBPLAN SCAN 算子上表示该算子从子节点读取的需要使用的列名。


查询执行计划详情实际上就是在查询 observer 内存中计划缓存中的计划信息。OB 使用虚拟表的机制为用户提供了一种通过 SQL 查询内存中数据的方法。那么每个虚拟表是怎么工作的就跟具体虚拟表的代码实现有关了,plan_cache_plan_explain 这个虚拟表就要求用户提供 (ip, port, tenant_id, plan_id) 这个四元组来进行查询。通常我们要查询 plan_cache_plan_explain 时,是要去查一个具体的计划的,而这个四元组可以唯一的定位到一个计划。

 


可以使用 outline 为 SQL 绑定一个 /*+max_concurrent(number)*/ 的 hint,hint 中的 number 表示的是 SQL 最大的并行度。


query range 表示的是根据过滤条件抽出的索引扫描的起点和终点。一个简单的例子是索引在 (a,b,c) 上有序,存在过滤条件

a = 1 and b > 1,那么这两个过滤条件就可以被抽成query range (1, 1, MAX; 1, MAX, MAX)。这个query range表示只要索引扫描从(a,b,c) = (1, 1, MAX)这个点开始扫描,一直扫描到(a,b,c) = (1, MAX, MAX)这个点结束,那么这两个点之间扫描出来的全部数据就是满足过滤条件a = 1 and b > 1
的数据。


在 OB 中标识符也是不区分大小写的。


社区版上手动收集统计信息支持的还不够完善,所以功能暂时关闭了。这一点直播的时候确实没有考虑到。