数据库在得到一个查询后,先将查询转化为一个逻辑查询计划,对其进行优化,然后转为物理执行计划,最后按照物理执行计划进行操作,最终得到最终结果。本篇博客介绍获得数据库查询计划的语法与物理计划的分类。
目录
- 得到查询执行计划的语法
- 物理执行计划的分类
- 从物理计划到最终结果
得到查询执行计划的语法
explain [sql cmd]; -- get the query plan on
explain analyze [sql cmd];
这两种语句针对不同数据库有不同结果,对于mysql而言,explain
得到的只是估计,explain analyze
包含真实执行后的时间,有时候使用explain
得到的估计不准确,这个时候我们可以调用语句analyze table [table name] update histogram on [col name];
更新对于表格某列的分布统计,进而使得explain
的结果更加符合实际情况。
在gaussdb上构建tpch数据库,尝试语句explain select * from lineitem where l_orderkey=1 limit 10;
得到如下图的查询计划(query plan),其中一共包括3行,代表在执行上述query时涉及到了3个算子,分别是limit
, seq scan
和filter
。
在mysql上尝试语句explain select * from aka_name where id < 10 limit 10;
得到如图结果:
运行explain format=tree select * from aka_name where id < 10 limit 10;
得到树状结构的分析结果,format
如果取值为json
则可以得到json
格式的结果。
运行语句explain analyze select * from aka_name where id < 10 limit 10;
得到如下结果:
物理执行计划的分类
其中计划节点类型分为四类:控制节点(Control Node),扫描节点(Scan Node),物化节点(Materialization Node),连接节点(Join Node)。
-
控制节点:append,组织多个字表或子查询的执行节点,主要用于union操作。
-
扫描节点:用于扫描表等对象以获取元组,具体分为:
- Seq Scan(全表扫描):把表的所有数据块从头到尾读一遍,筛选出符合条件的数据块;
- Index Scan(索引扫描):为了加快查询速度,在索引中找到需要的数据行的物理位置,再到表数据块中把对应数据读出来,如B树,GiST,GIN,BRIN,HASH;
- Bitmap Index/Heap Scan(位图索引/结果扫描):把满足条件的行或块在内存中建一个位图,扫描完索引后,再根据位图列表的数据文件把对应的数据读出来,先通过Bitmap Index Scan在索引中找到符合条件的行,在内存中建立位图,之后再到表中扫描Bitmap Heap Scan。
-
物化节点:能够缓存执行结果到缓存中,即第一次被执行时生成的结果元组缓存,等待上层节点使用,例如,sort节点能够获取下层节点返回的所有元组并根据指定的属性排序,并将排序结果缓存,每次上层节点取元组时就从缓存中按需读取。具体分为:
- Materialize:对下层节点返回的元组进行缓存(如连接表时)
- Sort:对下层返回的节点进行排序(如果内存超过iwork_mem参数指定大小,则节点工作空间切换到临时文件,性能急剧下降)
- Group:对下层排序元组进行分组操作
- Agg:执行聚集函数(sum/max/min/avg)
- 条件过滤,一般在where后加上过滤条件,当扫描数据行时,会找出满足过滤条件的行,条件过滤在执行计划里面显示Filter,如果条件的列上面有索引,可能会走索引,不会走过滤。
-
连接节点:对应于关系代数中的连接操作,可以实现多种连接方式(条件连接/左连接/右连接/全连接/自然连接)
- Nestedloop Join(嵌套连接): 内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大,要把返回子集较小的表作为外表,且内表的连接字段上要有索引。 执行过程为,确定一个驱动表(outer table),另一个表为inner table,驱动表中每一行与inner table中的相应记录关联;
- Hash Join(哈希连接):优化器使用两个比较的表,并利用连接属性在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行;
- Merge Join(合并连接):通常hash连接的性能要比merge连接好,但如果源数据上有索引,或结果已经被排过序,这时merge连接性能会优于hash连接;
从物理计划到最终结果
实现这一步有2种方法:
- 从物理计划得到对应的查询,然后执行查询得到结果
- 直接运行物理计划得到执行结果