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操作(例如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