控制联接输入
默认情况下,优化器使用自己的内部逻辑来确定将一个表作为内部输入还是外部输入联接到另一个表。有时,优化器可能选择将更大的表作为联接的内部输入。但这样做会导致性能和并发问题。
如果配置参数 EnableForceOuter
设置为 1,则您可以通过
ALTER TABLE..FORCE OUTER
控制特定表的联接输入。FORCE OUTER
选项会在
TABLES
系统表中修改表的 force_outer
设置。实施联接时,Vertica 会比较参与联接的表的 force_outer
设置:
-
如果表设置不同,Vertica 会使用它们来设置联接输入:
-
相比其他表具有较低
force_outer
设置的表会作为内部输入联接到这些表。 -
相比其他表具有较高
force_outer
设置的表会作为外部输入联接到这些表。
-
-
如果所有表设置都相同,Vertica 会忽略它们,然后自行决定如何构建联接。
对于所有新定义的表,force_outer
列最初都设置为 5。您可以使用
ALTER TABLE..FORCE OUTER
将 force_outer
重置为等于或大于 0 的值。例如,您可以将 abc
和 xyz
表的 force_outer
设置分别改为 3 和 8:
=> ALTER TABLE abc FORCE OUTER 3;
=> ALTER TABLE xyz FORCE OUTER 8;
根据这些设置,优化器会将 abc
作为内部输入联接到 force_outer
值大于 3 的任何表。优化器会将 xyz
作为外部输入联接到 force_outer
值小于 8 的任何表。
投影继承
直接查询投影时,它会继承其锚表的 force_outer
设置。然后查询会在联接到另一个投影后使用此设置。
启用强制联接输入
配置参数 EnableForceOuter
决定了 Vertica 是否使用表的 force_outer
值来实施联接。默认情况下,此参数设置为 0,并且强制联接输入处于禁用状态。您可以通过
ALTER SESSION
和
ALTER DATABASE
分别在会话和数据库范围中启用强制联接输入:
=> ALTER SESSION SET EnableForceOuter = { 0 | 1 };
=> ALTER DATABASE db-name SET EnableForceOuter = { 0 | 1 };
如果 EnableForceOuter
设置为 0,则 ALTER TABLE..FORCE OUTER
语句会返回以下警告:
注意
WARNING 0: Set configuration parameter EnableForceOuter for the current session or the database in order to use
force_outer value
查看强制联接输入
EXPLAIN
生成的查询计划会指示 EnableForceOuter
配置参数是否已启用。联接查询可能会包含 force_outer
设置小于或大于默认值 5 的表。在这种情况下,查询计划会包含相关联接查询的 Force outer level
字段。
例如,以下查询联接了 store.store_sales
表和 public.products
表,但这两个表具有相同的 force_outer
设置 (5)。EnableForceOuter
已启用,如生成的查询计划中所示:
=> EXPLAIN SELECT s.store_key, p.product_description, s.sales_quantity, s.sale_date
FROM store.store_sales s JOIN public.products p ON s.product_key=p.product_key
WHERE s.sale_date='2014-12-01' ORDER BY s.store_key, s.sale_date;
EnableForceOuter is on
Access Path:
+-SORT [Cost: 7K, Rows: 100K (NO STATISTICS)] (PATH ID: 1)
| Order: sales.store_key ASC, sales.sale_date ASC
| Execute on: All Nodes
| +---> JOIN HASH [Cost: 5K, Rows: 100K (NO STATISTICS)] (PATH ID: 2) Outer (BROADCAST)(LOCAL ROUND ROBIN)
| | Join Cond: (sales.product_key = products.product_key)
| | Execute on: All Nodes
| | +-- Outer -> STORAGE ACCESS for sales [Cost: 2K, Rows: 100K (NO STATISTICS)] (PATH ID: 3)
| | | Projection: store.store_sales_b0
| | | Materialize: sales.sale_date, sales.store_key, sales.product_key, sales.sales_quantity
| | | Filter: (sales.sale_date = '2014-12-01'::date)
| | | Execute on: All Nodes
| | +-- Inner -> STORAGE ACCESS for products [Cost: 177, Rows: 60K (NO STATISTICS)] (PATH ID: 4)
| | | Projection: public.products_b0
| | | Materialize: products.product_key, products.product_description
| | | Execute on: All Nodes
以下 ALTER TABLE
语句将 public.products
的 force_outer
设置重置为 1:
=> ALTER TABLE public.products FORCE OUTER 1;
ALTER TABLE
此时,为上述联接重新生成的查询包含 Force outer level
字段,并将 public.products
指定为内部输入:
=> EXPLAIN SELECT s.store_key, p.product_description, s.sales_quantity, s.sale_date
FROM store.store_sales s JOIN public.products p ON s.product_key=p.product_key
WHERE s.sale_date='2014-12-01' ORDER BY s.store_key, s.sale_date;
EnableForceOuter is on
Access Path:
+-SORT [Cost: 7K, Rows: 100K (NO STATISTICS)] (PATH ID: 1)
| Order: sales.store_key ASC, sales.sale_date ASC
| Execute on: All Nodes
| +---> JOIN HASH [Cost: 5K, Rows: 100K (NO STATISTICS)] (PATH ID: 2) Outer (BROADCAST)(LOCAL ROUND ROBIN)
| | Join Cond: (sales.product_key = products.product_key)
| | Execute on: All Nodes
| | +-- Outer -> STORAGE ACCESS for sales [Cost: 2K, Rows: 100K (NO STATISTICS)] (PATH ID: 3)
| | | Projection: store.store_sales_b0
| | | Materialize: sales.sale_date, sales.store_key, sales.product_key, sales.sales_quantity
| | | Filter: (sales.sale_date = '2014-12-01'::date)
| | | Execute on: All Nodes
| | +-- Inner -> STORAGE ACCESS for products [Cost: 177, Rows: 60K (NO STATISTICS)] (PATH ID: 4)
| | | Projection: public.products_b0
| | | Force outer level: 1
| | | Materialize: products.product_key, products.product_description
| | | Execute on: All Nodes
如果将 public.products
的 force_outer
设置更改为 8,Vertica 会创建将 public.products
指定为外部输入的另一个查询计划:
=> ALTER TABLE public.products FORCE OUTER 8;
ALTER TABLE
=> EXPLAIN SELECT s.store_key, p.product_description, s.sales_quantity, s.sale_date
FROM store.store_sales s JOIN public.products p ON s.product_key=p.product_key
WHERE s.sale_date='2014-12-01' ORDER BY s.store_key, s.sale_date;
EnableForceOuter is on
Access Path:
+-SORT [Cost: 7K, Rows: 100K (NO STATISTICS)] (PATH ID: 1)
| Order: sales.store_key ASC, sales.sale_date ASC
| Execute on: All Nodes
| +---> JOIN HASH [Cost: 5K, Rows: 100K (NO STATISTICS)] (PATH ID: 2) Inner (BROADCAST)
| | Join Cond: (sales.product_key = products.product_key)
| | Materialize at Output: products.product_description
| | Execute on: All Nodes
| | +-- Outer -> STORAGE ACCESS for products [Cost: 20, Rows: 60K (NO STATISTICS)] (PATH ID: 3)
| | | Projection: public.products_b0
| | | Force outer level: 8
| | | Materialize: products.product_key
| | | Execute on: All Nodes
| | | Runtime Filter: (SIP1(HashJoin): products.product_key)
| | +-- Inner -> STORAGE ACCESS for sales [Cost: 2K, Rows: 100K (NO STATISTICS)] (PATH ID: 4)
| | | Projection: store.store_sales_b0
| | | Materialize: sales.sale_date, sales.store_key, sales.product_key, sales.sales_quantity
| | | Filter: (sales.sale_date = '2014-12-01'::date)
| | | Execute on: All Nodes
限制
Vertica 在执行以下操作时会忽略 force_outer
设置:
-
外联接:无论已联接表的
force_outer
设置如何,Vertica 通常都会遵循OUTER JOIN
子句。 -
MERGE
语句联接。 -
包含
SYNTACTIC_JOIN
提示的查询。 -
半联接查询,例如
SEMI JOIN
。 -
联接到子查询,其中有一个子查询总是按
force_outer
设置为 5 进行处理,而不论在此子查询中已联接表的force_outer
设置如何。此设置决定了相对于其他联接输入,将子查询指定为内部还是外部输入。如果联接两个子查询,优化器会决定哪个是内部输入,哪个是外部输入。