写点什么

openGauss 内核分析(七):SQL by pass & 经典执行器 (一)

作者:daydayup
  • 2023-07-27
    北京
  • 本文字数:1837 字

    阅读完需:约 6 分钟

openGauss 内核分析(七):SQL by pass & 经典执行器 (一)

酷哥 [openGauss](javascript:void(0);) 2023-01-17 17:55 发表于广东


执行引擎一般负责查询的执行,执行引擎在 SQL 执行栈中起到接收优化器生成的执行计划 Plan、并对通过存储引擎提供的数据读写接口,实现对数据进行计算得到查询的结果集。



在典型的 OLTP 场景中,简单查询占了很大一部分比例。这种查询的特征是只涉及单表和简单表达式的查询,因此为了加速这类查询,openGauss 提出了 SQL by pass 框架,在 parse 层对这类查询做简单的模式判别后,进入到特殊的执行路径里,跳过经典的执行器执行框架,包括算子的初始化与执行、表达式与投影等经典框架,直接重写一套简洁的执行路径,并且直接调用存储接口,这样可以大大加速简单查询的执行速度。


01 SQL by pass


enable_opfusion 用于控制是否对简单增删改查进行优化,简单 insert 语句在开启 enable_opfusion 时的执行计划如下:



由于开启 SQL BY PASS,从 exec_simple_query 过来的语句,会判断可以走 SQL BY PASS,否则进入 CreatePortal 走经典执行流程。


static void exec_simple_query(const char* query_string, MessageType messageType, StringInfo msg = NULL){        /* SQL bypass */        if (runOpfusionCheck) { // 进入SQL by pass            (void)MemoryContextSwitchTo(oldcontext);            void* opFusionObj = OpFusion::FusionFactory(                OpFusion::getFusionType(NULL, NULL, plantree_list), oldcontext, NULL, plantree_list, NULL);            if (opFusionObj != NULL) {                ((OpFusion*)opFusionObj)->setCurrentOpFusionObj((OpFusion*)opFusionObj);                if (OpFusion::process(FUSION_EXECUTE, NULL, completionTag, isTopLevel, NULL)) {                    CommandCounterIncrement();                    finish_xact_command();                    EndCommand(completionTag, dest);                    MemoryContextReset(OptimizerContext);                    break;                }                Assert(0);            }            (void)MemoryContextSwitchTo(t_thrd.mem_cxt.msg_mem_cxt);        }        /*         * Create unnamed portal to run the query or queries in. If there         * already is one, silently drop it.         */        portal = CreatePortal("", true, true); // 经典执行流程
复制代码


进入 InsertFusion::execute 完成数据插入操作。


#0  InsertFusion::execute (this=0x7fd93a4104f8, max_rows=9223372036854775807, completionTag=0x7fd933e67020 "@p\346\063\331\177")    at opfusion_insert.cpp:297#1  0x0000000001ac00d9 in OpFusion::fusionExecute (this=0x7fd93a4104f8, msg=0x0, completionTag=0x7fd933e67020 "@p\346\063\331\177",    isTopLevel=true, isQueryCompleted=0x0) at opfusion.cpp:453#2  0x0000000001ac0389 in OpFusion::process (op=0, msg=0x0, completionTag=0x7fd933e67020 "@p\346\063\331\177", isTopLevel=true,    isQueryCompleted=0x0) at opfusion.cpp:491#3  0x000000000193a910 in exec_simple_query (query_string=0x7fd966ad2060 "insert into t1 values(1,200);",    messageType=QUERY_MESSAGE, msg=0x7fd933e67210) at postgres.cpp:2624
复制代码


SQL by pass 适应的场景有:


  • 只支持 indexscan 和 indexonlyscan,且全部 WHERE 语句的过滤条件都在索引上。

  • 只支持单表增删改查,不支持 join、using。

  • 只支持行存表,不支持分区表,表不支持有触发器。

  • 不支持 active sql、QPS 等信息统计特性。

  • 不支持正在扩容和缩容的表。

  • 不支持查询或者修改系统列。

  • 只支持简单 SELECT 语句,例如:


SELECT c3 FROM t1 WHERE c1 = ? and c2 =10;
复制代码


仅可以查询目标表的列,c1 和 c2 列为索引列,后边可以是常量或者参数,可以使用 for update。


  • 只支持简单 INSERT 语句,例如:


INSERT INTO t1 VALUES (?,10,?);
复制代码


仅支持一个 VALUES,VALUES 里面的类型可以是常量和参数,不支持 returning。


  • 只支持简单 DELETE 语句,例如:


DELETE FROM t1 WHERE c1 = ? and c2 = 10;
复制代码


c1 和 c2 列为索引列,后边可以是常量或者参数。


  • 只支持简单 UPDATE 语句,例如:


UPDATE t1 SET c3 = c3+? WHERE c1 = ? and c2 = 10;
复制代码


c3 列修改的值可以是常量和参数,也可以是一个简单的表达式,c1 和 c2 列为索引列,后边可以是常量或者参数。

用户头像

daydayup

关注

还未添加个人签名 2023-07-18 加入

还未添加个人简介

评论

发布
暂无评论
openGauss内核分析(七):SQL by pass & 经典执行器 (一)_daydayup_InfoQ写作社区