本页面介绍了如何在 AlloyDB for PostgreSQL 中创建和管理查询计划补丁。
查询计划补丁是指查询与一组提示之间的关联,可让您指定查询计划的详细信息。提示用于指定有关查询的首选最终执行计划的其他信息。例如,当您在查询中扫描表时,请使用索引扫描,而不是其他类型的扫描(例如顺序扫描)。
为了在提示的规范范围内限制最终的计划选择,查询规划器在生成执行计划时会先将提示应用于查询。然后,每当后续发出查询时,系统都会自动应用这些提示。 通过此方法,您可以强制规划器使用不同的查询计划。例如,您可以使用提示强制对某些表进行索引扫描,或强制在多个表之间使用特定的联接顺序。
AlloyDB 查询计划补丁支持 开源 pg_hint_plan
扩展程序中的所有提示。
此外,AlloyDB 还支持以下适用于列式引擎的提示:
ColumnarScan(table)
:强制对表进行列式扫描。NoColumnarScan(table)
:停用对表的列式扫描。
AlloyDB 允许您为参数化查询和非参数化查询创建方案补丁。在本页中,非参数化查询称为对参数敏感的查询。
工作流
使用查询计划补丁涉及以下步骤:
- 确定要为其创建计划补丁的查询。
- 创建包含提示的方案补丁,以便在下次执行查询时应用。
- 验证方案补丁的应用。
本页使用以下表和索引作为示例:
CREATE TABLE t(a INT, b INT);
CREATE INDEX t_idx1 ON t(a);
DROP EXTENSION IF EXISTS google_auto_hints;
如需继续使用您使用旧版创建的查询计划补丁,请按照本页中的说明重新创建这些补丁。
准备工作
在实例上启用查询计划补丁功能。将
alloydb.enable_query_plan_patch
标志设置为on
。您可以在服务器级层或会话级层启用此标志。为了最大限度地减少使用此功能可能产生的开销,请仅在会话级别启用此标志。如需了解详情,请参阅配置实例的数据库标志。
如需验证该标志是否已启用,请运行
show alloydb.enable_query_plan_patch;
命令。如果该标志已启用,则输出返回“on”。对于您要在其中使用查询计划补丁的每个数据库,请以
alloydbsuperuser
或postgres
用户的身份,从 AlloyDB 主实例在数据库中创建扩展程序:CREATE EXTENSION google_auto_hints CASCADE;
所需的角色
如需获得创建和管理查询计划补丁所需的权限,请让管理员向您授予以下 Identity and Access Management (IAM) 角色:
虽然默认权限仅允许具有 alloydbsuperuser
角色的用户创建方案补丁,但您可以选择向数据库的其他用户或角色授予写入权限,以便他们可以创建方案补丁。
GRANT INSERT,DELETE,UPDATE ON hint_plan.plan_patches, hint_plan.hints TO role_name;
GRANT USAGE ON SEQUENCE hint_plan.hints_id_seq, hint_plan.plan_patches_id_seq TO role_name;
确定查询
您可以使用查询 ID 来确定需要调整默认方案的查询。查询 ID 在查询至少执行一次后才会显示。
您可以使用以下方法来确定查询 ID:
运行
EXPLAIN (VERBOSE)
命令,如以下示例所示:EXPLAIN (VERBOSE) SELECT * FROM t WHERE a = 99; QUERY PLAN ---------------------------------------------------------- Seq Scan on public.t (cost=0.00..38.25 rows=11 width=8) Output: a, b Filter: (t.a = 99) Query Identifier: -6875839275481643436
在输出中,查询 ID 为
-6875839275481643436
。查询
pg_stat_statements
视图。如果您已启用
pg_stat_statements
扩展程序,则可以通过查询pg_stat_statements
视图来查找查询 ID,如以下示例所示:select query, queryid from pg_stat_statements;
创建查询计划补丁
如需创建查询计划补丁,请使用 google_create_plan_patch()
函数,该函数会在数据库中创建查询与提示之间的关联。
SELECT google_create_plan_patch(
PLAN_PATCH_NAME=>'PLAN_PATCH_NAME',
SQL_ID=>QUERY_ID,
SQL_TEXT=>QUERY_TEXT,
APPLICATION_NAME=>'APPLICATION_NAME',
HINTS=>'HINTS',
DISABLED=>DISABLED);
替换以下内容:
PLAN_PATCH_NAME
:方案补丁的名称。此值在数据库中必须是唯一的。SQL_ID
(可选):您要为其创建方案补丁的查询的查询 ID。您可以使用查询 ID 或查询文本(即
SQL_TEXT
参数)来创建方案补丁。 不过,我们建议您使用查询 ID 创建计划补丁,因为 AlloyDB 会根据查询 ID 自动找到规范化的查询文本。SQL_TEXT
(可选):您要为其创建计划补丁的查询的查询文本。使用查询文本时,该文本必须与预期查询相同,但查询中的字面量和常量值除外。任何不匹配(包括大小写差异)都可能导致方案补丁无法应用。如需了解如何为包含字面值和常量的查询创建计划补丁,请参阅创建参数敏感型查询计划补丁。
APPLICATION_NAME
(可选):您要使用计划补丁的会话客户端应用的名称。空字符串可让您将计划补丁应用于查询,而无论发出查询的客户端应用是什么。HINTS
:以空格分隔的查询提示列表。DISABLED
(可选):BOOL。如果值为TRUE
,则最初创建的方案补丁最初处于停用状态。
示例:
SELECT google_create_plan_patch(
PLAN_PATCH_NAME=>'my_hint1',
SQL_ID=>-6875839275481643436,
SQL_TEXT=>NULL,
APPLICATION_NAME=>'',
HINTS=>'IndexScan(t)',
DISABLED=>NULL);
此查询会创建一个名为 my_hint1
的方案补丁。其提示 IndexScan(t)
由规划器应用,以强制在下次运行此示例查询时对表 t
进行索引扫描。
创建方案补丁后,您可以使用 google_query_plan_patch_view
确认方案补丁是否已创建,如以下示例所示:
postgres=>\x
postgres=>select * from google_query_plan_patch_view limit 1;
-[ RECORD 1 ]-----+-----------------------------
plan_patch_name | my_hint1
sql_id | -6875839275481643436
id | 9
query_string | SELECT * FROM t WHERE a = ?;
application_name |
hints | IndexScan(t)
disabled | f
在主实例上创建方案补丁后,系统会自动将其应用于读取池实例上的相关查询,前提是您也在读取池实例上启用了查询方案补丁功能。
创建对参数敏感的查询计划补丁
默认情况下,当为查询创建计划补丁时,系统会通过将查询文本中的任何字面量和常量值替换为参数标记(例如 ?
)来对关联的查询文本进行标准化处理。然后,即使参数标记的值不同,该计划补丁也会用于相应标准化查询。
例如,运行以下查询可让其他查询(例如 SELECT * FROM t WHERE a = 99;
)默认使用执行计划补丁 my_hint2
。
SELECT google_create_plan_patch(
PLAN_PATCH_NAME=>'my_hint2',
SQL_ID=>NULL,
SQL_TEXT=>'SELECT * FROM t WHERE a = ?;',
APPLICATION_NAME=>'',
HINTS=>'SeqScan(t)',
DISABLED=>NULL);
然后,SELECT * FROM t WHERE a = 99;
等查询可以默认使用计划补丁 my_hint2
。
AlloyDB 还允许您为非形参化查询文本创建执行计划补丁,在这种情况下,查询文本中的每个字面值和常量值在匹配查询时都非常重要。
应用对形参敏感的计划补丁时,仅在相应字面值或常量值方面不同的两个查询也会被视为不同。如果您想强制执行两个查询的计划,则必须为每个查询分别创建计划补丁。不过,您可以为这两个计划补丁使用不同的提示。
如需创建对参数敏感的执行计划补丁,请将 google_create_plan_patch()
函数的 SENSITIVE_TO_PARAM
参数设置为 TRUE
,如以下示例所示:
SELECT google_create_plan_patch(
PLAN_PATCH_NAME=>'my_hint3',
SQL_ID=>NULL,
SQL_TEXT=>'SELECT * FROM t WHERE a = 88;',
APPLICATION_NAME=>'',
HINTS=>'IndexScan(t)',
DISABLED=>NULL,
SENSITIVE_TO_PARAM=>TRUE);
查询 SELECT * FROM t WHERE a = 99;
无法使用计划补丁 my_hint3
,因为字面量值“99”与“88”不匹配。
使用对参数敏感的执行计划补丁时,请考虑以下事项:
- 参数敏感型计划补丁不支持在查询文本中混合使用字面量值、常量值和参数标记。
- 如果您为同一查询创建了参数敏感型方案补丁和默认方案补丁,系统会优先选择参数敏感型方案补丁。
- 如果您想使用查询 ID 创建对形参敏感的计划补丁,请确保查询在当前会话中执行。系统会使用最近一次执行(在当前会话中)的形参值来创建计划补丁。
验证查询计划补丁的应用
创建计划补丁后,请使用以下方法验证查询计划是否已相应地强制执行。
使用
EXPLAIN
命令或EXPLAIN (ANALYZE)
命令。如需查看规划器尝试应用的提示,您可以在运行
EXPLAIN
命令之前在会话级层设置以下标志:SET pg_hint_plan.debug_print = ON; SET client_min_messages = LOG;
使用
auto_explain
扩展程序。
管理查询计划补丁
借助 AlloyDB,您可以查看、启用和停用以及删除查询计划补丁。
查看查询计划补丁
如需查看现有方案补丁,请使用 google_query_plan_patch_view
函数,如以下示例所示:
postgres=>\x
postgres=>select * from google_query_plan_patch_view limit 1;
-[ RECORD 1 ]-----+-----------------------------
plan_patch_name | my_hint1
sql_id | -6875839275481643436
id | 9
query_string | SELECT * FROM t WHERE a = ?;
application_name |
hints | IndexScan(t)
disabled | f
启用查询计划补丁
如需启用现有方案补丁,请使用 google_enable_plan_patch(PLAN_PATCH_NAME)
函数。默认情况下,在创建方案补丁时,系统会启用该补丁。
例如,如需从数据库中重新启用之前停用的计划补丁 my_hint1
,请运行以下函数:
SELECT google_enable_plan_patch('my_hint1');
停用查询计划补丁
如需停用现有方案补丁,请使用 google_disable_plan_patch(PLAN_PATCH_NAME)
函数。
例如,如需从数据库中删除示例计划补丁 my_hint1
,请运行以下函数:
SELECT google_disable_plan_patch('my_hint1');
删除查询计划补丁
如需删除方案补丁,请使用 google_delete_plan_patch(PLAN_PATCH_NAME)
函数。
例如,如需从数据库中删除示例计划补丁 my_hint1
,请运行以下函数:
SELECT google_delete_plan_patch('my_hint1');
停用查询计划补丁功能
如需在实例上停用查询计划补丁功能,请将 alloydb.enable_query_plan_patch
标志设置为 off
。如需了解详情,请参阅配置实例的数据库标志。
限制
使用查询计划补丁存在以下限制:
- 使用查询 ID 创建查询计划补丁时,原始查询文本的长度限制为 2048 个字符。
- 鉴于复杂查询的语义,并非所有提示及其组合都能完全应用。建议您先在查询中测试预期提示,然后再在生产环境中部署查询计划补丁。
- 强制执行复杂查询的联接顺序受到限制。
使用查询计划补丁来影响计划选择可能会干扰未来的 AlloyDB 优化器改进。 请务必在发生以下事件时重新考虑是否使用查询计划补丁,并相应地调整补丁:
- 工作负载发生了显著变化。
- 我们推出了新的 AlloyDB 版本或升级,其中涉及优化器更改和改进。
- 其他查询调优方法也适用于这些查询。
- 使用查询计划补丁会给系统性能带来显著的开销。
如需详细了解限制,请参阅 pg_hint_plan
文档。