GPORCA特性和增强
GPORCA是Greenplum的下一代查询优化器,它包括了对特定类型的查询和操作的增强:
GPORCA还包括下面这些优化增强:
- 改进的连接排序
- 连接-聚集重排序
- 排序顺序优化
- 查询优化中包括的数据倾斜估计
Parent topic: 关于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操作(例如INSERT,UPDATE和DELETE)的增强。
- 查询计划中的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