GPORCA特性和增强

GPORCA特性和增强

GPORCA是Greenplum的下一代查询优化器,它包括了对特定类型的查询和操作的增强:
GPORCA还包括下面这些优化增强:
  • 改进的连接排序
  • 连接-聚集重排序
  • 排序顺序优化
  • 查询优化中包括的数据倾斜估计

对分区表的查询

GPORCA包括这些对分区表上查询的增强:
  • 改进了分区消除。
  • 支持统一多级分区表。有关统一多级分区表的信息,请见关于统一多级分区表
  • 查询计划可以包含分区选择器操作符。
  • 不在EXPLAIN计划中枚举分区。
    对于涉及静态分区选择的查询,在其中会将分区键与常量进行比较,GPORCA会在EXPLAIN输出的分区选择器操作符下面列出要被扫描的分区数。这个示例分区选择器操作符展示了过滤条件和选中的分区数:
    Partition Selector for Part_Table (dynamic scan id: 1) 
           Filter: a > 10
    		   Partitions selected:  1 (out of 3)

    对于涉及动态分区选择的查询,在其中会将分区键与变量进行比较,要扫描的分区数只有在查询执行时才能知道。选中的分区不会显示在EXPLAIN输出中。

  • 计划尺寸与分区数无关。
  • 由于分区数导致的内存不足错误被减少。

这个CREATE TABLE命令的例子创建一个范围分区表。

CREATE TABLE sales(order_id int, item_id int, amount numeric(15,2), 
      date date, yr_qtr int)
   range partitioned by yr_qtr;

GPORCA改进了针对分区表的这些类型的查询:

  • 全表扫描。计划中不会枚举分区。
    SELECT * FROM sales;
  • 带一个常量过滤谓词的查询。会执行分区消除。
    SELECT * FROM sales WHERE yr_qtr = 201501;
  • 范围选择。会执行分区消除。
    SELECT * FROM sales WHERE yr_qtr BETWEEN 201601 AND 201704 ;
  • 涉及到分区表的连接。在下面这个例子中,分区过的维度表date_dim 被连接到事实表catalog_sales
    SELECT * FROM catalog_sales
       WHERE date_id IN (SELECT id FROM date_dim WHERE month=12);

含有子查询的查询

GPORCA更有效地处理子查询。子查询是嵌套在外层查询块里面的查询。在下面的查询中,WHERE子句中的SELECT是一个子查询。
SELECT * FROM part
  WHERE price > (SELECT avg(price) FROM part);
GPORCA还能更有效地处理含有相关子查询(CSQ)的查询。相关子查询是使用来自外层查询的值的子查询。在下面的查询中,price列被使用在外层查询和子查询中。
SELECT * FROM part p1
  WHERE price > (SELECT avg(price) FROM part p2 
  WHERE  p2.brand = p1.brand);
GPORCA为下列类型的子查询生成更有效的计划:
  • SELECT列表中的CSQ。
    SELECT *,
     (SELECT min(price) FROM part p2 WHERE p1.brand = p2.brand)
     AS foo
    FROM part p1;
  • 析取(OR)过滤条件中的CSQ。
    SELECT FROM part p1 WHERE p_size > 40 OR 
          p_retailprice > 
          (SELECT avg(p_retailprice) 
              FROM part p2 
              WHERE p2.p_brand = p1.p_brand)
  • 具有越级关联的嵌套CSQ
    SELECT * FROM part p1 WHERE p1.p_partkey
    IN (SELECT p_partkey FROM part p2 WHERE p2.p_retailprice = 
         (SELECT min(p_retailprice)
           FROM part p3 
           WHERE p3.p_brand = p1.p_brand)
    );
    Note: 传统查询优化器不支持具有越级关联的嵌套CSQ。
  • 有聚集和不等于的CSQ。下面这个例子包含一个有不等于的CSQ。
    SELECT * FROM part p1 WHERE p1.p_retailprice =
     (SELECT min(p_retailprice) FROM part p2 WHERE p2.p_brand <> p1.p_brand);
  • 必须返回一行的CSQ。
    SELECT p_partkey,
      (SELECT p_retailprice FROM part p2 WHERE p2.p_brand = p1.p_brand )
    FROM part p1;

含有公共表表达式的查询

GPORCA处理含有WITH子句的查询。WITH子句也被称为公共表表达式(CTE),它会生成只在该查询中存在的临时表。下面这个查询例子包含一个CTE。
WITH v AS (SELECT a, sum(b) as s FROM T where c < 10 GROUP BY a)
  SELECT *FROM  v AS v1 ,  v AS v2
  WHERE v1.a <> v2.a AND v1.s < v2.s;
作为查询优化的一部分,GPORCA可以把谓词下推到一个CTE中。对于下面的例子查询,GPORCA把等于谓词推到了CTE。
WITH v AS (SELECT a, sum(b) as s FROM T GROUP BY a)
  SELECT *
  FROM v as v1, v as v2, v as v3
  WHERE v1.a < v2.a
    AND v1.s < v3.s
    AND v1.a = 10
    AND v2.a = 20
    AND v3.a = 30;
GPORCA可以处理这些类型的CTE:
  • 定义一个或者多个表的CTE。在下面的这个查询中,CTE定义两个表。
    WITH cte1 AS (SELECT a, sum(b) as s FROM T
                   where c < 10 GROUP BY a),
          cte2 AS (SELECT a, s FROM cte1 where s > 1000)
      SELECT *
      FROM cte1 as v1, cte2 as v2, cte2 as v3
      WHERE v1.a < v2.a AND v1.s < v3.s;
  • 嵌套CTE。
    WITH v AS (WITH w AS (SELECT a, b FROM foo 
                          WHERE b < 5) 
               SELECT w1.a, w2.b 
               FROM w AS w1, w AS w2 
               WHERE w1.a = w2.a AND w1.a > 2)
      SELECT v1.a, v2.a, v2.b
      FROM v as v1, v as v2
      WHERE v1.a < v2.a; 

GPORCA的DML操作增强

GPORCA含有对DML操作(例如INSERTUPDATEDELETE)的增强。
  • 查询计划中的DML节点是一个查询计划操作符。
    • 可以作为一个常规节点(目前只有顶层切片)出现在计划中的任何地方
    • 可以有消费者
  • UPDATE操作使用查询计划操作符Split并且支持这些操作:
    • 表的分布键列上的UPDATE操作。
    • 表的分区键列上的UPDATE操作。
    这个计划的例子展示了Split操作符。
    QUERY PLAN
    --------------------------------------------------------------
    Update  (cost=0.00..5.46 rows=1 width=1)
       ->  Redistribute Motion 2:2  (slice1; segments: 2)
             Hash Key: a
             ->  Result  (cost=0.00..3.23 rows=1 width=48)
                   ->  Split  (cost=0.00..2.13 rows=1 width=40)
                         ->  Result  (cost=0.00..1.05 rows=1 width=40)
                               ->  Seq Scan on dmltest
  • 新的查询计划操作符Assert被用于约束检查。
    这个计划的例子展示了Assert操作符。
    QUERY PLAN
    ------------------------------------------------------------
     Insert  (cost=0.00..4.61 rows=3 width=8)
       ->  Assert  (cost=0.00..3.37 rows=3 width=24)
             Assert Cond: (dmlsource.a > 2) IS DISTINCT FROM 
    false
             ->  Assert  (cost=0.00..2.25 rows=3 width=24)
                   Assert Cond: NOT dmlsource.b IS NULL
                   ->  Result  (cost=0.00..1.14 rows=3 width=24)
                         ->  Seq Scan on dmlsource