Fixed Plan加速SQL执行

Fixed Plan是Hologres特有的执行引擎优化方式,本文将为您介绍可以被Fixed Plan选中的SQL需要符合的条件和参数配置。

背景信息

Fixed Plan是Hologres特有的执行引擎优化方式,传统的SQL执行要经过优化器、协调器、查询引擎、存储引擎等多个组件,而Fixed Plan选择了短路径(Short-Cut)优化执行SQL,绕过了优化器、协调器、部分查询引擎的开销。通过Fixed FrontEnd直接对接Fixed Query Engine,实现SQL执行效率的成倍提升,是支持高吞吐实时写入,高并发查询的关键优化方法。关于Fixed Plan的介绍请参见产品架构

在Hologres中,默认走Fixed Plan的场景如下:

  • Flink实时写入数据至Hologres。

  • DataWorks数据集成实时写入数据至Hologres。

  • Holo Client写入Hologres。

其余写入场景可根据SQL进行一定的配置让其走Fixed Plan,详情请参见下文。

说明

以上场景会默认保证符合条件的SQL走Fixed Plan,但是以上场景的SQL不一定都符合条件即不一定都能走Fixed Plan。

相关GUC参数

  • GUC列表

    以下为Fixed Plan需要用到的参数配置,所有参数取值为on或者off。所有参数已经在Holo Client中默认打开,Session级别生效。

    GUC名称

    适用场景

    默认值

    GUC变更记录

    hg_experimental_enable_fixed_dispatcher

    查看实例的Fixed Plan是否打开。

    支持Insert、Update、Delete、PrefixScan场景单行记录的Fixed Plan写入、更新、删除、查询。

    on

    不涉及。

    hg_experimental_enable_fixed_dispatcher_for_multi_values

    控制Insert多行记录的Fixed Plan写入。

    说明

    不保证原子性,即一次性写入多条的时候,如果没报错就是全部正常写入了,如果报错了只会报一条的错误,有可能全部没写入也有可能部分写入了部分没写入,没有写入的部分会将错误反馈给上层应用端,由应用端进行重试。

    on

    Hologres从V1.3.35版本开始,通过该GUC支持Insert、Update、Delete多行记录的Fixed Plan写入、更新、删除。

    hg_experimental_enable_fixed_dispatcher_autofill_series

    支持含有Serial类型列的Fixed Plan写入。建议客户端session级别打开。

    off

    Hologres从V1.3.25版本开始,该GUC参数的默认值为on

    hg_experimental_enable_fixed_dispatcher_for_update

    支持更新(UPDATE)场景的Fixed Plan更新。建议客户端session级别打开。

    off

    Hologres从V1.3.25版本开始,hg_experimental_enable_fixed_dispatcher_for_update废弃使用,即符合条件的UPDATE语句会默认使用Fixed Plan,但UPDATE多行记录需要配置set hg_experimental_enable_fixed_dispatcher_for_multi_values =on

    hg_experimental_enable_fixed_dispatcher_for_delete

    支持删除(DELETE)场景的Fixed Plan删除。建议客户端session级别打开。

    off

    Hologres从V1.3.25版本开始,hg_experimental_enable_fixed_dispatcher_for_delete废弃使用即符合条件的DELETE语句会默认走Fixed Plan,但DELETE多行记录需要配置set hg_experimental_enable_fixed_dispatcher_for_multi_values =on

    hg_experimental_enable_fixed_dispatcher_for_scan

    支持PrefixScan场景的Fixed Plan查询。

    说明

    PrefixScan是指多列主键,查询条件只给前面几列主键。目前不支持列存表PrefixScan场景的Fixed Plan查询。

    off

    推荐从1.3.35版本开始使用。

    hg_experimental_enable_bhclient_cache_on_session

    支持更改缓存模式,存在以下两种情况。

    • on:使用cached on session模式。

    • off:使用cached on fe模式。

    说明

    cached on sessioncached on fe的区别如下。

    • cached on session是每个连接拥有自己的Writer、Reader,单连接的吞吐更好,但启动会更慢(每个表第一次进行读或写时需要有启动时间)。

    • cached on fe是FE(Frontend)节点上所有连接共享Writer、Reader,连接断开后Writer、Reader不会关闭,所以总体上没有启动时间。

    off

    不涉及。

    hg_experimental_disable_fixed_planner_conflict_pk_check

    控制INSERT INTO <table_name> VALUES (...) ON CONFLICT(<column>)语法中的column是否支持非主键字段。

    • false:不支持。

    • true:支持。

      说明

      该GUC参数设置为true,column支持填写非主键字段,但INSERT ON CONFLICT语句实际执行时,还是按照主键是否重复(ON CONFLICT(pk))来处理数据。

    false

    • Hologres从V1.3至V2.1.28版本,ON CONFLICT(<column>)中的字段必须为主键字段。

    • Hologres从V2.1.29版本开始,通过该GUC参数控制ON CONFLICT(<column>)中的字段是否支持非主键字段。

  • GUC使用

    • 查看GUC是否开启

      通过show命令查看GUC是否开启,命令语句如下。

      SHOW <GUC_name>;

      使用示例如下。

      -- 查看实例级别是否开启Fixed Plan
      SHOW hg_experimental_enable_fixed_dispatcher;
    • 开启GUC

      • session级别开启GUC

        通过set命令可以在session级别设置GUC参数。session级别的参数只在当前session生效,当连接断开之后,将会失效,建议加在SQL前一起执行,语法示例如下。

        SET <GUC_name> = <values>;

        GUC_name为GUC参数的名称;values为GUC参数的值。

        使用示例如下。

        -- insert on conflict多行记录支持Fixed Plan写入
        SET hg_experimental_enable_fixed_dispatcher_for_multi_values =on;
      • 数据库级别开启GUC

        通过alter database xx set xxx命令来设置数据库级别的GUC参数,执行完成后在整个数据库生效,设置完成后当前连接需要重新断开连接才能生效。新建数据库不会生效,需要重新手动设置,语法示例如下。

        ALTER database <db_name> SET <GUC_name> = <values>;

        db_name为数据库名称,GUC_name为GUC参数的名称,values为GUC参数的值。

        使用示例如下。

        --DB级别开启fixed plan
        ALTER database <db_name> SET hg_experimental_enable_fixed_dispatcher =on;

数据类型要求

  • 表的每一列都不能是MONEY或MONEY ARRAY类型。

  • 进行DML(INSERT、UPDATE、DELETE)操作的列和进行SELECT(select的target列和where里的列都要满足)操作的列支持的类型如下。

    • BOOLEAN(别名BOOL)

    • SMALLINT

    • INTEGER(别名INT或INT4)

    • BIGINT(别名INT8)

    • FLOAT(别名FLOAT4)

    • DOUBLE PRECISION(别名FLOAT8)

    • CHAR(n)

    • VARCHAR(n)

    • BYTEA

    • JSON和JSONB

    • TEXT(别名VARCHAR)

    • TIMESTAMP WITH TIME ZONE(别名TIMESTAMPTZ)

    • DATE

    • TIMESTAMP

    • DECIMAL(别名NUMERIC)

    • ROARINGBITMAP

    • TIME(Hologres V2.2版本开始支持)

    • TIMETZ(Hologres V2.2版本开始支持)

    • 数组类型

      • boolean[]

      • smallint[]

      • int4[]

      • int8[]

      • float4[]

      • float8[]

      • char(n)[]

      • varchar(n)[]

      • text[]

INSERT场景

  • INSERT表达式

    Fixed Plan支持以下INSERT表达式。

    -- 写入单行
    INSERT INTO TABLE(col1,col2,col3..) VALUES(?,?,?..) ON conflict xxx;
    -- 写入多行
    INSERT INTO TABLE(col1,col2,col3..) VALUES(?,?,?..),(?,?,?..) ON conflict xxx;
    说明
    • 支持使用INSERT命令写入内部表,不支持外部表。

    • 支持使用INSERT命令写入分区表,Hologres V1.3及以上版本支持写入分区父表。

  • Insert on conflict单行

    • 支持场景如下。

      • 支持没有on conflict的表达式。

      • 支持含有on conflict do nothing的表达式。

      • 支持on conflict do update,必须更新所有insert的非PK(Primary Key,主键,以下简称PK)列,PK是否更新都可以,并且只能是col = excluded.col方式更新。Hologres V1.3及以上版本支持更新部分非PK列,但是仍仅支持col = excluded.col方式更新

    • 使用示例如下。

      BEGIN;
      CREATE TABLE test_insert_oneline (
          pk1 int,
          pk2 int,
          col1 int,
          col2 int,
          PRIMARY KEY (pk1, pk2)
      );
      COMMIT;
      
      --update所有非PK列,可以Fixed Plan
      INSERT INTO test_insert_oneline
          VALUES (1, 2, 3, 4)
      ON CONFLICT (pk1, pk2)
          DO UPDATE SET
              col1 = excluded.col1, col2 = excluded.col2;
      
      --update所有列(包含PK和非PK),可以Fixed Plan
      INSERT INTO test_insert_oneline
          VALUES (1, 2, 3, 4)
      ON CONFLICT (pk1, pk2)
          DO UPDATE SET
              col1 = excluded.col1, col2 = excluded.col2, pk1 = excluded.pk1, pk2 = excluded.pk2;
      
      --必须update所有非pk的要insert的列,此例子不包含col2,仅Hologres V1.3仅以上版本支持Fixed Plan
      INSERT INTO test_insert_oneline
          VALUES (1, 2, 3, 4)
      ON CONFLICT (pk1, pk2)
          DO UPDATE SET
              col1 = excluded.col1;
      
      --必须是set col = excluded.col方式更新,因此不能Fixed Plan
      INSERT INTO test_insert_oneline
          VALUES (1, 2, 3, 4)
      ON CONFLICT (pk1, pk2)
          DO UPDATE SET
              col1 = excluded.col1, col2 = 5;
  • Insert on conflict多行

    • insert on conflict多行时,表达式如下。

      SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
      
      INSERT INTO TABLE (col1, col2, col3..)
          VALUES (?, ?, ?..), (?, ?, ?..)
      ON CONFLICT xxx;
      • 需要配置GUC参数:hg_experimental_enable_fixed_dispatcher_for_multi_values=on;。Hologres从1.3.35开始,该参数默认为on

      • 不保证原子性,即一次性写入多条的时候,如果没报错就是全部正常写入了,如果报错了有可能全部没写入也有可能部分写入了部分没写入。

    • 写入多行另一种写法表达式如下。

      SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
      
      INSERT INTO TABLE selectunnest (ARRAY[TRUE, FALSE, TRUE]::bool[]), unnest(ARRAY[1, 2, 3]::int4[]), unnest(ARRAY[1.11, 2.222, 3]::float4[])
      ON CONFLICT xxx;
      
      • 需要配置GUC参数:hg_experimental_enable_fixed_dispatcher_for_multi_values=on;

      • 写入的列不能是数组类型。

      • unnest里ARRAY必须显式转换为对应列类型的数组类型。

      使用示例如下。

      BEGIN;
      CREATE TABLE test_insert_multiline (
          pk1 int8,
          col1 float4,
          PRIMARY KEY (pk1)
      );
      COMMIT;
      
      --支持Fixed Plan
      SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
      
      INSERT INTO test_insert_multiline
      SELECT
          unnest(ARRAY[1, 2, 3]::int8[]),
          unnest(ARRAY[1.11, 2.222, 3]::float4[])
      ON CONFLICT
          DO NOTHING;
      
      --unnest里ARRAY没有显式cast,不支持Fixed Plan
      INSERT INTO test_insert_multiline
      SELECT
          unnest(ARRAY[1, 2, 3]),
          unnest(ARRAY[1.11, 2.222, 3])
      ON CONFLICT
          DO NOTHING;
      
      --第一列是int8,所以应该cast为int8[],这里例子是int4[],因此不支持Fixed Plan
      INSERT INTO test_insert_multiline
      SELECT
          unnest(ARRAY[1, 2, 3]::int4[]),
          unnest(ARRAY[1.11, 2.222, 3]::float4[])
      ON CONFLICT
          DO NOTHING;
  • 局部更新场景

    Hologres支持通过主键,对表的部分列更新,Fixed Plan同样支持局部更新场景,需要满足如下条件。

    • Insert的列需要与Update的列一一对应,包括数量和顺序。

    • 只能是col = excluded.col方式更新。

  • 带有条件判断的Upsert

    为了应对上游数据同PK行的乱序需求,支持类HBase CheckAndPut接口,Hologres支持带有条件判断的InsertUpdate语句走Fixed Plan,条件如下。

    • 插入单条数据时支持;插入多条数据时,需要设置GUC参数:set hg_experimental_enable_fixed_dispatcher_for_multi_values=on;

    • where条件仅支持单个非PK字段且比较符需在=、<>、>、>=、<、<=、IS NULL、IS NOT NULL范围内 ,可对该非PK字段使用coalesce函数。

    使用示例如下。

    BEGIN;
    CREATE TABLE test_check_and_insert (
        pk int,
        col int,
        scn int,
        PRIMARY KEY (pk)
    );
    COMMIT;
    
    --支持Fixed Plan
    --列已有值和常量比较
    INSERT INTO test_check_and_insert AS old
        VALUES (1, 1, 1)
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col, scn = excluded.scn
        WHERE
            old.scn > 0;
    
    --列已有值和写入值比较
    INSERT INTO test_check_and_insert AS old
        VALUES (1, 1, 1)
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col, scn = excluded.scn
        WHERE
            old.scn > excluded.scn;
    
    --若已有值可能为null,可用coalesce
    INSERT INTO test_check_and_insert AS old
        VALUES (1, 1, 1)
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col, scn = excluded.scn
        WHERE
            coalesce(old.scn, 3) > 2;
    
    INSERT INTO test_check_and_insert AS old
        VALUES (1, 1, 1)
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col, scn = excluded.scn
        WHERE
            coalesce(old.scn, 3) > excluded.scn;
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
    
    --列已有值和常量比较
    INSERT INTO test_check_and_insert AS old
        VALUES (1, 1, 1), (2, 3, 4)
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col, scn = excluded.scn
        WHERE
            old.scn > 3;
    
    --也支持unnest写法
    INSERT INTO test_check_and_insert AS old
    SELECT
        unnest(ARRAY[5, 6, 7]::int[]),
        unnest(ARRAY[1, 1, 1]::int[]),
        unnest(ARRAY[1, 1, 1]::int[])
    ON CONFLICT (pk)
        DO UPDATE SET
            col = excluded.col,
            scn = excluded.scn
        WHERE
            old.scn > 3;
    
  • Default列

    表中含有Default列时,可以进行Fixed Plan的条件如下。

    • 插入单条数据时支持;插入多条数据时,需要Hologres实例在V1.1.36及以上版本,若低于此版本请升级实例。同时需要设置GUC参数:set hg_experimental_enable_fixed_dispatcher_for_multi_values=on;

    • Hologres V1.3及以上版本支持有Default列的表insert on conflict表达式的Fixed Plan。之前版本实例有Default列的表,不支持insert on conflict表达式的Fixed Plan。

    使用示例如下。

    BEGIN;
    CREATE TABLE test_insert_default (
        pk1 int,
        col1 int DEFAULT 99,
        PRIMARY KEY (pk1)
    );
    COMMIT;
    
    --支持Fixed Plan
    INSERT INTO test_insert_default (pk1)
        VALUES (1);
    
    --需要V1.1.36及以上版本支持
    SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
    
    INSERT INTO test_insert_default (pk1)
        VALUES (1), (2), (3);
  • Serial列

    表带有自增序列Serial时,支持单条或者多条写入进行Fixed Plan的条件如下。

    • 需要配置GUC参数:set hg_experimental_enable_fixed_dispatcher_autofill_series=on;,从Hologres V1.3.25版本开始,该GUC参数默认为on

    • 插入多条数据时,还需配置GUC参数:set hg_experimental_enable_fixed_dispatcher_for_multi_values=on;

    使用示例如下。

    BEGIN;
    CREATE TABLE test_insert_serial (
        pk1 int,
        col1 serial,
        PRIMARY KEY (pk1)
    );
    COMMIT;
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_autofill_series = ON;
    
    INSERT INTO test_insert_serial (pk1)
        VALUES (1);
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_autofill_series = ON;
    
    SET hg_experimental_enable_fixed_dispatcher_for_multi_values = ON;
    
    INSERT INTO test_insert_serial (pk1)
        VALUES (1), (2), (3);
    

UPDATE场景

  • Update表达式

    Update时能进行Fixed Plan的表达式如下。

    SET hg_experimental_enable_fixed_dispatcher_for_update = ON;
    
    UPDATE TABLE SET col1 = ?,col2 = ? WHERE pk1 = ? AND pk2 = ?;
  • Update场景使用

    Update场景支持进行Fixed Plan的条件如下。

    • 支持更新内部表,不支持更新外部表;支持更新分区子表,不支持更新分区父表;表必须有主键(PK)。

    • 需要配置GUC参数:hg_experimental_enable_fixed_dispatcher_for_update=on; 。Hologres从 V1.3.25版本开始,该参数废弃使用,符合条件的Update则会默认走Fixed Plan,但如果是Update更新多行时,需要配置GUC参数:set hg_experimental_enable_fixed_dispatcher_for_multi_values =on

    • set的列不能是主键(PK)。

    • where条件里有且只能有全部的PK。

    • 可以使用pk in (?,?,?) 或 pk = ANY() 一次修改多条。示例:pk1 in (1,2) and pk2 = any('{3,4}') and pk3 = 5,改(1,3,5),(1,4,5),(2,3,5),(2,4,5)四条。

    • where条件里同一列只能有一个条件(一模一样的视为一个条件)。

    使用示例如下。

    BEGIN;
    CREATE TABLE test_update (
        pk1 int,
        pk2 int,
        col1 int,
        col2 int,
        PRIMARY KEY (pk1, pk2)
    );
    COMMIT;
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_for_update = ON;
    
    UPDATE
        test_update
    SET
        col1 = 1,
        col2 = 2
    WHERE
        pk1 = 3
        AND pk2 = 4;
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_for_update = ON;
    
    UPDATE
        test_update
    SET
        col1 = 1
    WHERE
        pk1 = 3
        AND pk2 = 4;
    
    --支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_for_update = ON;
    
    UPDATE
        test_update
    SET
        col1 = 1,
        col2 = 2
    WHERE
        pk1 IN (1, 2)
        AND pk2 = ANY ('{3,4}');
    
    --pk1多个过滤条件,不支持Fixed Plan
    UPDATE
        test_update
    SET
        col1 = 1,
        col2 = 2
    WHERE
        pk1 = 3
        AND pk1 = 4;
    
    --pk1多个过滤条件,不支持Fixed Plan
    UPDATE
        test_update
    SET
        col1 = 1,
        col2 = 2
    WHERE
        pk1 IN (1, 2)
        AND pk1 = 1;
    
    --pk1多个过滤条件,但过滤条件相同,支持Fixed Plan
    SET hg_experimental_enable_fixed_dispatcher_for_update = ON;
    
    UPDATE
        test_update
    SET
        col1 = 1,
        col2 = 2
    WHERE
        pk1 IN (1, 2)
        AND pk1 IN (1, 2)
        AND pk2 = 4;
    

DELETE场景

  • Delete表达式

    Delete时能进行Fixed Plan的表达式如下。

    SET hg_experimental_enable_fixed_dispatcher_for_delete = ON;
    
    DELETE FROM TABLE
    WHERE pk1 = ?
        AND pk2 = ?
        AND pk3 = ?;
  • Delete场景使用

    Delete场景支持进行Fixed Plan的条件如下。

    • 支持Delete内部表,不支持Delete外部表;支持Delete分区子表,不支持Delete分区父表;表必须有主键(PK)。

    • 需要配置GUC参数:hg_experimental_enable_fixed_dispatcher_for_delete=on; 。Hologres从 V1.3.25版本开始,该参数废弃使用,符合条件的Delete则会默认走Fixed Plan,但如果是Delete多行时,需要配置GUC参数:set hg_experimental_enable_fixed_dispatcher_for_multi_values =on

    • where条件里有且只能有全部的PK,从Hologres V1.3版本开始,支持where过滤条件的最后一个字段为非PK字段,该非PK字段支持=、<>、>、>=、<、<=、IS NULL、IS NOT NULL 比较符以及使用coalesce函数。

    • 可以使用pk in (?,?,?) 或 pk = ANY() 一次删除多条。示例:pk1 in (1,2) and pk2 = any('{3,4}') and pk3 = 5 ,删除(1,3,5),(1,4,5),(2,3,5),(2,4,5)四条。

    • 同一列只能有一个条件(一模一样的视为一个条件)。

    使用示例如下。

    BEGIN;
    CREATE TABLE test_delete (
        pk1 int,
        pk2 int,
        col1 int,
        col2 int,
        PRIMARY KEY (pk1, pk2)
    );
    COMMIT;
    
    --支持Fixed Plan,更多场景与Update样例一致
    SET hg_experimental_enable_fixed_dispatcher_for_delete = ON;
    
    DELETE FROM test_delete
    WHERE pk1 = 1
        AND pk2 = 2;
    

SELECT场景

  • SELECT表达式

    SELECT时能进行Fixed Plan的表达式如下。

    SELECT
        col1,
        col2,
        col3,
    ...
    FROM
        TABLE
    WHERE
        pk1 = ?
        AND pk2 = ?
        AND pk3 = ?;
    
    • 支持Select内部表,不支持外部表。

    • 支持分区子表,不支持分区父表。

    • 表必须有主键(PK)。

  • 点查(key/value)场景

    点查场景支持的情况如下。

    • where条件里有且只能有全部的PK。

    • 可以使用pk in (?,?,?) 或 pk = ANY() 一次查多条。示例: pk1 in (1,2) and pk2 = any('{3,4}') and pk3 = 5,查(1,3,5),(1,4,5),(2,3,5),(2,4,5)四条。

    • 同一列只能有一个条件(一模一样的视为一个条件)。

    • 如果有limit,limit的值必须>0

    使用示例如下。

    BEGIN;
    CREATE TABLE test_select (
        pk1 int,
        pk2 int,
        col1 int,
        col2 int,
        PRIMARY KEY (pk1, pk2)
    );
    CALL set_table_property ('test_select', 'orientation', 'row');
    COMMIT;
    
    --支持Fixed Plan
    SELECT * FROM test_select WHERE pk1 = 1 AND pk2 = 2;
  • PrefixScan场景

    • PrefixScan场景表达式

      PrefixScan场景是指表有多个主键,查询时按照左匹配原则只查几列主键,查询表达式如下。

      SET hg_experimental_enable_fixed_dispatcher_for_scan = on;
      SELECT col1,col2,col3,... FROM TABLE WHERE pk1 = ? AND pk2 = ?;
      SELECT col1,col2,col3,... FROM TABLE WHERE pk1 = ? AND pk2 < ?;--从1.1.48版本开始支持pk最后一列条件为range
      SELECT col1,col2,col3,... FROM TABLE WHERE pk1 = ? AND pk2 BETWEEN ? AND ?;--从1.1.48版本开始支持pk最后一列条件为range                                
    • PrefixScan使用

      PrefixScan的使用条件如下。

      • 需要配置GUC参数:hg_experimental_enable_fixed_dispatcher_for_scan=on;,且实例在V1.3.35版本以上。

      • 表必须有Distribution Key,且where语句里必须包含所有的Distribution Key。

      • where语句里有且只有PK的Prefix。PrefixScan从V1.1.48版本开始支持主键最后一列条件设置为范围(同时包含上限和下限)。

        说明

        Prefix定义: 若PK为(pk1,pk2,pk3),则(pk1),(pk1,pk2)为Prefix。

      • 仅行存表(包括行列共存)支持PrefixScan。

      • 同一列只能有一个条件(一模一样的视为一个条件)。

      • 如果含有limit条件,limit的值必须大于0。

      说明

      PrefixScan一次性返回所有结果行,如果结果的字节数大于hg_experimental_fixed_scan_bytesize_limit会报错:scan result size larger than fixed scan size limit ,可以通过配置hg_experimental_fixed_scan_bytesize_limit参数设置更符合场景的值,默认值为1048576,即1MB。

      示例如下,若表PK为(pk1,pk2,pk3,pk4), Distribution Key为pk1,pk3

      BEGIN;
      CREATE TABLE test_select_prefix (
          pk1 int,
          pk2 int,
          pk3 int,
          pk4 int,
          PRIMARY KEY (pk1, pk2, pk3, pk4)
      );
      CALL set_table_property ('test_select_prefix', 'orientation', 'row');
      CALL set_table_property ('test_select_prefix', 'distribution_key', 'pk1,pk3');
      COMMIT;
      
      --没有包含所有distribution key,不能走fixed plan
      SELECT * FROM test_select_prefix WHERE pk1 = ? AND pk2 = ?;
      --不是pk的prefix,不能走fixed plan
      SELECT * FROM test_select_prefix WHERE pk1 = ? AND pk3 = ?;
      
      --可以走fixed plan
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_select_prefix WHERE pk1 = ? AND pk2 = ? AND pk3 = ?;
      

      可以使用pk in (?,?,?)pk = ANY()一次性查多条,命令如下。

      pk1 IN (1,2) AND pk2 = 3 <=> scan(1,3),(2,3)两组
      pk2 =any('{3,4}') AND pk1 IN (1,2) <=> scan(1,3),(1,4),(2,3),(2,4)四组
    • 使用示例

      BEGIN;
      CREATE TABLE test_scan (
          pk1 int,
          pk2 int,
          pk3 int,
          col1 int,
          PRIMARY KEY (pk1, pk2, pk3)
      );
      CALL set_table_property ('test_scan', 'orientation', 'row');
      CALL set_table_property ('test_scan', 'distribution_key', 'pk1,pk2');
      COMMIT;
      
      INSERT INTO test_scan
          VALUES (1, 2, 3, 4);
      
      --支持Fixed Plan
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_scan WHERE pk1 = 1 AND pk2 = 2;
      
      --支持Fixed Plan
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_scan WHERE pk1 = 1 AND pk2 IN (2, 3);
      
      --支持Fixed Plan
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_scan WHERE pk1 = ANY ('{3,4}') AND pk2 IN (2, 3);
      
      --支持fixed plan,pk最后一列是range条件,需要1.1.48及以上版本支持
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_scan WHERE pk1 = 1 AND pk2 = 1 AND pk3 > 1 AND pk3 < 4;
      
      --支持fixed plan,pk最后一列是range条件,需要1.1.48及以上版本支持
      SET hg_experimental_enable_fixed_dispatcher_for_scan = ON;
      
      SELECT * FROM test_scan WHERE pk1 = 1 AND pk2 = 1 AND pk3 BETWEEN 1 AND 4;
      
      --不包含所有的distribution key,不支持Fixed Plan
      SELECT * FROM test_scan WHERE pk1 = 1;
      
      --不符合主键前缀Prefix,不支持Fixed Plan
      SELECT * FROM test_scan WHERE pk2 = 2;

COPY场景

Hologres从1.3.17版本开始,COPY语句支持走Fixed Plan,与非Fixed Plan相比差异如下。

对比项

Fixed Plan

非Fixed Plan

锁类型

行锁

表锁

数据可见行

写入即可见。

Copy命令执行结束后可见。

性能

非常高

支持类型

TEXT或BINARY

TEXT

支持的主键冲突策略

支持如下策略:

  • NONE:主键发生冲突报错。

  • IGNORE:主键发生冲突则对该数据执行跳过操作。

  • UPDATE:主键发生冲突则对该数据执行更新操作。

NONE(冲突则报错)

COPY语句新增如下参数。

参数

说明

stream_mode

是否走Fixed Plan,取值如下。

  • true:走Fixed Plan。

  • false:不走Fixed Plan。

on_conflict

冲突策略,取值如下:

  • NONE:主键发生冲突报错。

  • IGNORE:主键发生冲突则对该数据执行跳过操作。

  • UPDATE:主键发生冲突则对该数据执行更新操作。

命令示例如下。

COPY table_name (column0, column1, column2)
FROM
    STDIN WITH (
        format BINARY,
        stream_mode TRUE,
        on_conflict UPDATE);

非全列表现说明。

  • 如果Copy写入的列不是全列,则为局部更新,表现如下:

    CREATE TABLE t0 (
        id int NOT NULL,
        name text,
        age int,
        PRIMARY KEY (id)
    );
    
    COPY t0 (id,
        name)
    FROM
        STDINWITH (stream_mode TRUE, on_conflict UPDATE);
    
    -- 上述COPY等价与如下
    INSERT INTOINSERT INTO t0 (id, name)
        VALUES (?, ?)
    ON CONFLICT (id)
        DO UPDATE SETid = excluded.id, name = excluded.name;
  • 如果Copy写入的列不是全列,且未参与写入的列设置了默认值属性,表现如下:

    CREATE TABLE t0 (
        id int NOT NULL,
        name text,
        age int DEFAULT 0,
        PRIMARY KEY (id)
    );
    
    COPY t0 (id,
        name)
    FROM
        STDINWITH (stream_mode TRUE, on_conflict UPDATE);
    
    -- 上述COPY等价与如下INSERT INTO
    -- 若id数据不存在,age列赋值default value;
    -- 若id数据已存在,age列不更新
    INSERT INTO t0 (id, name, age)
        VALUES (?, ?, DEFAULT)
    ON CONFLICT (id)
        DO UPDATE SETid = excluded.id, name = excluded.name;
    

验证Fixed Plan

  • 通过FixedPlan执行的更新类SQL,在控制台的实时导入RPS面板中会显示为SDK类型,包括INSERT、UPDATE和DELETE类型的操作。建议实时写入类Insert、Update、Delete都尽量优化为Fixed Plan方案,改善数据更新的效率。RPS

  • 通过查看SQL执行计划(explain sql),如果返回的执行计划中含有FixedXXXNode,即表示触发了Fixed Plan,如下图所示。如未生成含有FixedXXXNode的执行计划,请对照上文场景支持条件, 查看是否满足条件。验证fixedplan

性能调优

在某些场景上若是已经开启Fixed Plan但还需要做性能调优时,可选择如下方式。

  • Hologres V1.1.49版本开始针对Fixed Plan点查场景进行了优化,在大规模点查的情况下提升了30%以上吞吐。若有需要请升级实例至V1.1.49及以上版本。

  • 客户端合理的攒批(使用Holo Client会自动攒批),即一次执行SQL命令的数量,实践证明数量为512或者512的倍数性能会更好。

常见问题

  • 问题1:连接报错:role/database does not exist.

    • 原因:用户或DB不存在。

    • 解决办法:检查连接信息,填写正确的用户名或DB名。

      您可以登录Hologres管理控制台,单击目标实例操作列中的管理,然后单击数据库管理,在用户管理 DB 授权页面获取并确认用户名或DB名。

  • 问题2:数据写入过程中报错:the requested table name: xxx (id: xx, version: xx) mismatches the version of the table (id: xx, version: xx) from server.

    • 原因:数据写入过程中表元信息发生变化(如增加列)导致Table Version发生变化。

    • 解决方案:重新建立连接,Fixed Plan会获取新的表元信息并进行写入。