优化器提示
本文介绍了 MAXIR 支持的优化器提示及使用方法。
概述
MAXIR 自身提供了一个强大的查询优化器,用于确定 SQL 命令执行的最有效方式。但是也存在优化器选择的查询计划不是最高效的执行方式的情况。在这种情况下,可以使用优化器提示来指导优化器执行特定操作。
优化器提示是一种特殊的指示,可以嵌入到 SQL 命令中,以指导查询优化器如何执行查询。下表提供了 MAXIR 提供的优化器提示的一般信息。
| 名称 | 描述 | 适用范围 |
|---|---|---|
| [SET](#SET 提示) | 临时设置系统变量的会话值。 | 查询 |
| [JOIN_ORDER](#JOIN_ORDER 提示) | 指定查询块中的连接顺序。 | 查询块 |
| REPLICATED, PARTITIONED | 设置连接的分布类型。 | 查询块 |
作为一种特殊的注释类型,优化器提示必须在 /*+ ... */ 中指定。允许空格。例如:
/*+SET (<var_name>, '<value>')[,...]*/SET 提示
SET 提示临时为查询指定系统变量的会话值。
语法
SET 提示的语法是:
SET (<var_name>, '<value>')在这个语法中,
-
<var_name>:指定系统变量的名称。 -
<value>:指定此系统变量的新会话值。
一个 SET 提示只能用于设置一个每会话系统变量。如果你想设置多个,可以在一个提示块中(即,一个 /*+ ... */ 注释)以逗号分隔的列表中指定多个 SET 提示。以下是两个例子:
/*+SET(statistics_cpu_timer_enabled,'true'), SET(query_max_memory, '1GB' )*/
SELECT * FROM sales使用注意事项
目前,SET 提示必须放在查询的最开始。
如果一个提示块包含重复的 SET 提示,只有最后一个会生效。
如果一个提示块包含冲突的 SET 提示,只有最后一个会生效。
一个查询最多可以强制执行一个 SET 提示块。如果你在一个查询中指定了多个提示块,只有第一个提示块会生效。例如:
/*+SET(statistics_cpu_timer_enabled,'true')*/
/*+SET(task_concurrency, '1')*/
SELECT * FROM sales在这个例子中,只有 SET(statistics_cpu_timer_enabled,'true') 会生效。 SET (task_concurrency, '1' ) 将被忽略。
示例
将会话变量 preferred_tablescan_read_batch_rows 设置为 40480:
/*+SET(preferred_tablescan_read_batch_rows,'40480')*/
SELECT 123.456E7 from DUALJOIN_ORDER 提示
JOIN_ORDER 提示影响 MAXIR 优化器连接表的顺序,其范围是查询块。
语法
JOIN_ORDER (<left_t>, <right_t>);-
left_t:连接的左边的表或列表。 -
right_t:连接的右边的表或列表。
如果 <left_t> 或 <right_t> 是一组表,你必须使用括号包围它们。如果列表中包含两个以上的表,你必须使用多级括号,以便在每对括号中只有两个元素(一个表或一对括号中的内容被视为一个元素)。最内层括号中的表或元素将首先被连接。
例如:
JOIN_ORDER (a, (b, c))在这个例子中,<left_t> 是 a,<right_t> 是 (b, c)。这个提示指定 a 与 b 和 c 的连接结果连接。
再举一个例子:
JOIN_ORDER ((a, (b, c)),(d, e))在这个例子中,<left_t> 是 (a, (b, c)),<right_t> 是 (d, e)。这个提示指定 a 与 b 和 c 的连接结果在左边,而 d 与 e 在右边,然后左边的结果与右边的结果连接。
然而,JOIN_ORDER (a, (b, c), d) 是无效的,因为它包含三个元素。
使用注意事项
如果存在以下任何条件,JOIN_ORDER 提示将被忽略:
-
任何指定表的名称或别名不存在。
-
它包含重复的表名或别名。
-
它没有包含查询块中指定的所有表。
假设查询块的当前连接顺序是
a INNER JOIN b INNER JOIN c。如果你为查询块设置了/*+ JOIN_ORDER (a, b) */,提示将被忽略。在这个例子中,正确的JOIN_ORDER提示是:/*+ JOIN_ORDER (c, (a, b)) */。
如果一个表有一个别名,JOIN_ORDER 提示必须引用这个别名。
每次只能对每个查询块执行一个 JOIN_ORDER 提示。如果你在一个查询块中指定了多个 JOIN_ORDER 提示,只有第一个 JOIN_ORDER 会生效。
示例
使用 JOIN_ORDER 提示首先连接表 orders 和 customer,然后与表 lineitem 连接:
SELECT
/*+JOIN_ORDER(lineitem,(orders,customer))*/
l_orderkey,
sum(
l_extendedprice * (1 - l_discount)
) AS revenue,
o_orderdate,
o_shippriority
FROM
customer,
orders,
lineitem
WHERE
c_mktsegment = 'BUILDING'
AND c_custkey = o_custkey
AND l_orderkey = o_orderkey
AND o_orderdate < date '1995-03-15'
AND l_shipdate > date '1995-03-15'
GROUP BY
l_orderkey,
o_orderdate,
o_shippriority
ORDER BY
revenue DESC,
o_orderdate
LIMIT
10;连接分布类型提示
MAXIR 提供了两个用于配置连接分布类型的提示:REPLICATED 和 PARTITIONED。 REPLICATED 提示将连接的分布类型设置为 REPLICATED。 PARTITIONED 提示将连接的分布类型设置为 PARTITIONED。
语法
/*+ [REPLICATED | PARTITIONED] (<join_order>)[, ... ] */在这个语法中,
-
REPLICATED:将指定连接的分布类型设置为REPLICATED。 -
PARTITIONED:将指定连接的分布类型设置为PARTITIONED。 -
<join_order>:指定分布类型适用的连接顺序。有关连接顺序的使用注意事项的详细信息,请参见
JOIN_ORDER部分中描述的 使用注意事项。
在一个提示块中,你可以指定多个分布类型提示。例如:
/*+ REPLICATED (a, (b, c)), PARTITIONED (b, c) */使用注意事项
如果一个提示块中指定的两个提示互相冲突,只有第一个提示会生效。例如:
/*+ REPLICATED (a, b), PARTITIONED (a, b) */在这个例子中,只有第一个提示 REPLICATED (a, b) 会生效。
在某些情况下,连接的分布类型是确定的,不能通过这样的提示进行修改。例如,a CROSS JOIN b 的分布类型只能是 REPLICATED。在这个例子中,设置 PARTITIONED (a, b) 提示没有效果。
如果指定的连接顺序不存在,提示是无效的。
示例
将 orders JOIN customer 的分布类型设置为 PARTITIONED,将 lineitem JOIN (orders JOIN customer) 的分布类型设置为 REPLICATED:
SELECT
/*+REPLICATED(l,(o,c)), PARTITIONED(o,c)*/
l.orderkey,
sum(l.extendedprice * (1 - l.discount)) AS revenue,
o.orderdate,
o.shippriority
FROM customer AS c,
orders AS o,
lineitem AS l
WHERE c.mktsegment = 'BUILDING'
AND c.custkey = o.custkey
AND l.orderkey = o.orderkey
AND o.orderdate < DATE '1995-03-15'
AND l.shipdate > DATE '1995-03-15'
GROUP BY l.orderkey,
o.orderdate,
o.shippriority
ORDER BY revenue DESC,
o.orderdate LIMIT 10
;