对 INSERT INTO ... SELECT 查询的 SELECT 部分使用并行执行可以提升 AlloyDB for PostgreSQL 查询性能,尤其是在处理分区表和复杂查询时。
通过并行化 SELECT 子计划,数据库可以使用多个工作器进程来检索数据。然后,数据库会将检索到的数据插入到目标表中。这种分工可以提高数据库性能。
PostgreSQL 中的并行查询计划如何运作
在 PostgreSQL 中,查询优化器可以为整个查询或部分查询创建并行计划。生成并行执行计划时,系统会在执行计划顶部添加 Gather 或 Gather Merge 节点。
此节点可协调多个并行工作器进程。每个工作器都会执行任务的一部分,例如扫描表的一部分。然后,Gather 节点会从所有工作器收集结果,并将这些结果传递给查询的下一阶段或传递回客户端。
例如,以下查询计划显示了一个 Gather 节点,该节点计划使用五个工作进程对表 t1 执行并行顺序扫描。
EXPLAIN SELECT * FROM t1;
QUERY PLAN
-------------------------------------------------------------
Gather (cost=0.00..143359.76 rows=9999878 width=60)
Workers Planned: 5
-> Parallel Seq Scan on t1 (cost=0.00..143359.76 rows=1999976 width=60)
(3 rows)
针对 INSERT...SELECT 语句的并行执行
AlloyDB 通过使用多个工作进程来并行化 SELECT 语句,从而提高 INSERT INTO ... SELECT 性能。这种分工有助于提高数据库性能。
查询必须是并行安全的,并且不得有任何条件会阻止并行化。
许多数据库操作都使用 INSERT INTO ... SELECT 语句向表中添加新行。通常,语句的 SELECT 部分是查询中最耗费资源的部分。
该功能由以下配置参数控制:
enable_parallel_select_for_insert_select:启用或停用相应功能。在 PostgreSQL 14 及更高版本中,此参数默认处于启用状态。enable_parallel_select_for_insert_select_into_part_table:启用或停用允许您插入分区表的功能。在 PostgreSQL 16 及更高版本中,此参数默认处于关闭状态。
为了让查询规划工具考虑并行计划,INSERT SELECT 语句必须是并行安全的。这意味着,操作的任何部分都不能包含无法安全并行执行的函数或表达式。如果查询的任何部分被确定为并行不安全,优化器会回退到非并行计划。如需了解详情,请参阅并行安全性。
阻止并行执行的条件
如果 INSERT SELECT 语句被视为并行不安全,查询优化器不会使用并行计划。以下情况会阻止并行化:
- 目标表是外部表。
- 该查询使用包含数据修改语句(例如
DELETE)的可修改通用表表达式 (CTE)。 - 目标表上的索引使用了并行不安全表达式或函数。
- 目标表中的某个列具有使用并行不安全函数的默认值。
- 目标表上的触发器使用了并行不安全表达式或函数。
- 目标表有一个 DOMAIN 列,该列具有使用并行不安全函数的
CHECK约束。 - 目标表上的
CHECK限制包含并行不安全表达式或函数。 - 目标表是分区表,且
enable_parallel_select_for_insert_select_into_part_table已停用。
准备工作
本文档假定您已拥有 AlloyDB 数据库。如需创建数据库,请参阅创建集群及其主实例和创建和管理数据库。
所需的角色
如需获得在会话级更改数据库标志所需的权限,请让管理员为您授予项目的 AlloyDB Database User (roles/alloydb.databaseUser) Identity and Access Management (IAM) 角色。如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。
启用并行执行参数
如需为分区目标表启用并行执行,请按以下步骤操作:
在 Google Cloud 控制台中,前往集群页面。
从列表中选择一个集群。
在导航菜单中,点击 AlloyDB Studio。
使用您的数据库名称、用户名和密码登录 AlloyDB Studio。
将
enable_parallel_select_for_insert_select_into_part_tableGUC 设置为on。SET enable_parallel_select_for_insert_select_into_part_table = on;启用 GUC 参数后,如果查询被确定为并行安全,查询规划器会自动考虑目标为分区表的
INSERT INTO ... SELECT语句的并行计划。以下示例会生成一个 EXPLAIN 计划,其中显示了一个 Gather 节点,表明
source_table中的SELECT是并行执行的。-- Create a partitioned table CREATE TABLE part_table (a INT, b TEXT) PARTITION BY RANGE (a); CREATE TABLE part_table_1 PARTITION OF part_table FOR VALUES FROM (MINVALUE) TO (1000); CREATE TABLE part_table_2 PARTITION OF part_table FOR VALUES FROM (1000) TO (MAXVALUE); -- Create a source table CREATE TABLE source_table (c1 INT, c2 TEXT); INSERT INTO source_table SELECT i, 'value_' || i FROM generate_series(1, 2000) i; ANALYZE source_table; -- Enable the feature SET enable_parallel_select_for_insert_select_into_part_table = on; -- Optional for parallelizing the query with a small amount of data SET parallel_setup_cost=0; SET parallel_tuple_cost=0; SET min_parallel_table_scan_size=0; -- Run the insert with a parallelizable select EXPLAIN INSERT INTO part_table SELECT * FROM source_table;这会返回以下输出:
EXPLAIN (COSTS OFF) INSERT INTO part_table SELECT * FROM source_table; QUERY PLAN ----------------------------------------------- Insert on part_table -> Gather Workers Planned: 2 -> Parallel Seq Scan on source_table (4 rows)
停用并行执行参数
如需停用相应参数,请按以下步骤操作:
在 Google Cloud 控制台中,前往集群页面。
从列表中选择一个集群。
在导航菜单中,点击 AlloyDB Studio。
使用您的数据库名称、用户名和密码登录 AlloyDB Studio。
如需停用
enable_parallel_select_for_insert_select参数,请运行以下 SQL 命令:SET enable_parallel_select_for_insert_select = OFF;如需停用
enable_parallel_select_for_insert_select_into_part_table参数,请运行以下 SQL 命令:SET enable_parallel_select_for_insert_select_into_part_table = OFF;
验证并行方案
您可以使用 EXPLAIN 命令验证优化器是否正在使用并行计划。在查询计划中查找 Gather 节点以及 Workers Planned 或 Workers Launched 属性。
标准表格示例
在以下方案示例中,系统会启动六个工作器进程,以并行哈希联接方式执行 SELECT 语句。
EXPLAIN (ANALYZE)
INSERT INTO t1 SELECT t2.* FROM t1, t2 WHERE t1.c1 != t2.c1 AND t1.c2 = t2.c2;
QUERY PLAN
------------------------------------------------------------------------------------
Insert on t1 (cost=1209138.00..12801765.49 rows=0 width=0) (actual time=16812.677..19337.150 rows=0 loops=1)
-> Gather (cost=1209138.00..12801765.49 rows=99995407 width=24) (actual time=16812.674..19337.144 rows=0 loops=1)
Workers Planned: 6
Workers Launched: 6
-> Parallel Hash Join (...)
(...)
分区表示例
以下示例显示,在为分区表启用该功能后,执行计划会显示一个 Gather 节点,其中包含 SELECT 的四个计划工作器。
-- First, enable the feature for partitioned tables
SET enable_parallel_select_for_insert_select_into_part_table = ON;
-- Then, explain the query
EXPLAIN (COSTS OFF) INSERT INTO part_table SELECT * FROM source_table;
QUERY PLAN
-----------------------------------------------
Insert on part_table
-> Gather
Workers Planned: 2
-> Parallel Seq Scan on source_table
(4 rows)
后续步骤
- 详细了解并行安全。