G.3. pgpro_multiplan — save query execution plans and prepared statements for future usage #
- G.3.1. Description
- G.3.2. Installation
- G.3.3. Supported Modes and Plan Types
- G.3.4. Frozen Plan Usage
- G.3.5. Baseline Usage
- G.3.6. Frozen Plan Backups
- G.3.7. Compatibility with Other Extensions
- G.3.8. Query Identification
- G.3.9. Automatic Type Casting
- G.3.10. Plan Usage Statistics
- G.3.11. Integration with AQE
- G.3.12. Global Prepared Statements
- G.3.13. Views
- G.3.14. Functions
- G.3.15. Configuration Parameters
- G.3.2. Installation
G.3.1. Description #
The pgpro_multiplan extension allows you to save query execution plans and use them for subsequent executions of the same queries, thereby avoiding repeated optimization of identical queries. It can also be used to lock a specific execution plan if a plan chosen by the planner does not suit your needs for some reasons. pgpro_multiplan works similar to Oracle SQL Plan Management.
This extension also allows you to store global prepared statements created in different database sessions and share these statements between multiple sessions.
G.3.2. Installation #
The pgpro_multiplan extension is provided with Postgres Pro Enterprise as a separate pre-built package pgpro-multiplan-ent-17 (for the detailed installation instructions, see Chapter 17). To enable pgpro_multiplan, complete the following steps:
Add the library name to the
shared_preload_librariesvariable in thepostgresql.conffile:shared_preload_libraries = 'pgpro_multiplan'
Note that the library names in the
shared_preload_librariesvariable must be added in the specific order, for information on compatibility of pgpro_multiplan with other extensions, see Section G.3.7.Reload the database server for the changes to take effect.
To verify that the
pgpro_multiplanlibrary was installed correctly, you can run the following command:SHOW shared_preload_libraries;
Create the pgpro_multiplan extension using the following query:
CREATE EXTENSION pgpro_multiplan;
It is essential that the library is preloaded during server startup because pgpro_multiplan has a shared memory cache that can be initialized only during startup. The pgpro_multiplan extension should be created in each database where query management is required.
Enable the pgpro_multiplan extension, which is disabled by default.
To activate one or two modes related to the use of different plans and their statistics, specify the pgpro_multiplan.mode parameter. For more information, see Supported Modes and Plan Types.
To enable the use of global prepared statements, set the pgpro_multiplan.global_prepared_statements parameter to
on.You can specify these parameters in one of the following ways:
at server startup (in the
postgresql.conffile) to apply them to all sessionsin the current session using the
SETcommand
If you want to transfer pgpro_multiplan data from the primary to a standby using physical replication, set the pgpro_multiplan.wal_rw parameter to
onon both servers. In this case, ensure that the same pgpro_multiplan versions are installed on both primary and standby, otherwise correct replication workflow is not guaranteed.
G.3.3. Supported Modes and Plan Types #
The pgpro_multiplan extension supports the following plans:
Frozen plans: Locked plans that are given priority when executing the corresponding queries. A query can have one frozen plan only. pgpro_multiplan provides the following types of frozen plans:
serialized: A serialized representation of the plan. This plan is converted into an executable plan the first time the corresponding query is matched. Serialized plans remain valid as long as the query metadata (table structures, indexes, etc.) remain unchanged. For example, if a table referenced in the frozen plan is recreated, the frozen plan becomes invalid and is ignored. Serialized plans are only valid within the current database and cannot be copied to another, as they depend on OIDs. For this reason, using serialized plans for temporary tables is impractical.hintset: A set of hints that are formed based on the execution plan at the time of freezing. The set of hints includes optimizer environment variables differing from default values, join types, join orders, and data access methods. These hints correspond to those supported by the pg_hint_plan extension. To use hint-set plans, pg_hint_plan must be enabled. When the corresponding frozen query is matched, the hints are passed to pg_hint_plan to generate the executable plan. If the pg_hint_plan extension is not active, the hints are ignored, and the plan generated by the Postgres Pro optimizer is executed. Hint-set plans do not depend on object identifiers and remain valid when tables are recreated, fields are added, etc.template: A special case of thehintsetplan. These plans can be applied only to queries with table names matching the regular expression specified in the pgpro_multiplan.wildcards configuration parameter. Thepgpro_multiplan.wildcardsvalue is frozen along with the corresponding query.
Baselines: Sets of allowed plans that can be used to execute queries if there are no corresponding frozen plans. Like
hintsetfrozen plans, baselines rely on planner hints and require the pg_hint_plan extension to be enabled. If pg_hint_plan is not active, the hints are ignored, and the plan generated by the Postgres Pro optimizer is executed.
Use the pgpro_multiplan.mode configuration parameter to specify a comma-separated list of enabled modes and plan types. By default, this parameter is set to an empty string, which means that all plan modes are disabled.
G.3.4. Frozen Plan Usage #
To enable the use of frozen plans, specify the frozen value in the pgpro_multiplan.mode parameter.
To freeze a plan for future usage, perform the following steps:
G.3.4.1. Registering a Query #
There are the following ways to register a query:
Using the pgpro_multiplan_register_query() function:
SELECT pgpro_multiplan_register_query(
query_string,parameter_type, ...);Here
query_stringis your query with$parameters (same as innPREPARE). You can describe each parameter type with the optionalstatement_nameASparameter_typeargument of the function or choose not to define parameter types explicitly. In the latter case, Postgres Pro attempts to determine each parameter type from the context. This function returns the unique pair ofsql_hashandconst_hash. Now pgpro_multiplan will track executions of queries that fit the saved parameterized query template.-- Create table 'a' CREATE TABLE a AS (SELECT * FROM generate_series(1,30) AS x); CREATE INDEX ON a(x); ANALYZE; -- Register the query SELECT sql_hash, const_hash FROM pgpro_multiplan_register_query('SELECT count(*) FROM a WHERE x = 1 OR (x > $2 AND x < $1) OR x = $1', 'int', 'int'); sql_hash | const_hash -----------------------+------------- -6037606140259443514 | 2413041345 (1 row)Using the pgpro_multiplan.auto_tracking parameter:
-- Set pgpro_multiplan.auto_tracking to on SET pgpro_multiplan.auto_tracking = on; -- Execute EXPLAIN for a non-parameterized query EXPLAIN SELECT count(*) FROM a WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22; Custom Scan (MultiplanScan) (cost=1.60..0.00 rows=1 width=8) Plan is: tracked SQL hash: 5393873830515778388 Const hash: 0 Plan hash: 0 -> Aggregate (cost=1.60..1.61 rows=1 width=8) -> Seq Scan on a (cost=0.00..1.60 rows=2 width=0) Filter: ((x = $1) OR ((x > $2) AND (x < $3)) OR (x = $4)) -- Disable pgpro_multiplan.auto_tracking SET pgpro_multiplan.auto_tracking = off;
All registered queries are stored in the local cache that can be accessed using the pgpro_multiplan_local_cache view.
G.3.4.2. Modifying the Query Execution Plan #
A query execution plan can be modified using optimizer variables, pg_hint_plan hints if the extension is enabled, or other extensions that allow changing the query plan, such as aqo. For information on compatibility of pgpro_multiplan with other extensions, see Section G.3.7.
G.3.4.3. Freezing the Query Execution Plan #
To freeze a modified query plan, use the pgpro_multiplan_freeze function. The optional plan_type parameter can be set to either serialized, hintset, or template. The default value is serialized. For detailed information on types of frozen plans, see Section G.3.3.
All frozen plans are stored in the pgpro_multiplan_storage view.
G.3.4.4. Frozen Plan Example #
The example below illustrates how to use frozen plans.
-- A plan that needs to be improved
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a
WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22;
QUERY PLAN
-------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Seq Scan on a (actual rows=12 loops=1)
Filter: ((x = 1) OR ((x > 11) AND (x < 22)) OR (x = 22))
Rows Removed by Filter: 18
Planning Time: 0.179 ms
Execution Time: 0.069 ms
(6 rows)
-- Make sure that you set a required mode for pgpro_multiplan
SET pgpro_multiplan.mode = 'frozen';
-- Register the query
SELECT sql_hash, const_hash
FROM pgpro_multiplan_register_query('SELECT count(*) FROM a
WHERE x = 1 OR (x > $2 AND x < $1) OR x = $1', 'int', 'int');
sql_hash | const_hash
----------------------+------------
-6037606140259443514 | 2413041345
(1 row)
-- Modify the query execution plan
-- Force index scan by disabling sequential scan
SET enable_seqscan = 'off';
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a
WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22;
QUERY PLAN
----------------------------------------------------------------------------
Custom Scan (MultiplanScan) (actual rows=1 loops=1)
Plan is: tracked
SQL hash: -6037606140259443514
Const hash: 2413041345
Plan hash: 0
-> Aggregate (actual rows=1 loops=1)
-> Index Only Scan using a_x_idx on a (actual rows=12 loops=1)
Filter: ((x = 1) OR ((x > $2) AND (x < $1)) OR (x = $1))
Rows Removed by Filter: 18
Heap Fetches: 30
Planning Time: 0.235 ms
Execution Time: 0.099 ms
(12 rows)
-- Restore the seqscan ability
RESET enable_seqscan;
-- Freeze the query execution plan
SELECT pgpro_multiplan_freeze();
pgpro_multiplan_freeze
------------------------
t
(1 row)
-- The frozen plan with indexscan is now used
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a
WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22;
QUERY PLAN
----------------------------------------------------------------------------
Custom Scan (MultiplanScan) (actual rows=1 loops=1)
Plan is: frozen, serialized
SQL hash: -6037606140259443514
Const hash: 2413041345
Plan hash: 0
-> Aggregate (actual rows=1 loops=1)
-> Index Only Scan using a_x_idx on a (actual rows=12 loops=1)
Filter: ((x = 1) OR ((x > $2) AND (x < $1)) OR (x = $1))
Rows Removed by Filter: 18
Heap Fetches: 30
Planning Time: 0.063 ms
Execution Time: 0.119 ms
(12 rows)
G.3.5. Baseline Usage #
If there is no frozen plan for a specific query, the pgpro_multiplan extension can use a baseline, that is, a set of allowed plans created by the standard planner. You can also enable real-time plan management that adds plans produced by AQE to the list of allowed plans automatically.
To enable the use of allowed plans, specify the baseline value in the pgpro_multiplan.mode parameter.
To add the plan created by the standard planner to the set of allowed plans, follow these steps:
For subsequent queries, the created plan is applied without modification if it is in the set of allowed plans. If there is no such plan, the cheapest plan from the set of allowed plans is used.
Note
Allowed plans can be used only when pg_hint_plan extension is active. For more information, see the Compatibility with Other Extensions section. Allowed plans are not used if automatic capturing is enabled. Do not forget to disable the pgpro_multiplan.auto_capturing parameter after completing the capture.
G.3.5.1. Capturing a Plan #
The pgpro_multiplan.auto_capturing parameter allows capturing all executed queries. You can access all captured queries using the pgpro_multiplan_captured_queries view.
-- Create table 'a'
CREATE TABLE a AS SELECT x, x AS y FROM generate_series(1,1000) x;
CREATE INDEX ON a(x);
CREATE INDEX ON a(y);
ANALYZE;
-- Enable the auto_capturing parameter
SET pgpro_multiplan.mode = 'baseline'
SET pgpro_multiplan.auto_capturing = 'on';
-- Execute the query
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 900;
count
-------
100
(1 row)
-- Execute it again with different constants to get a different plan
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 10 AND t2.y > 900;
count
-------
0
(1 row)
-- Now you can see the captured plans using the corresponding view
SELECT * FROM pgpro_multiplan_captured_queries \gx
dbid | 5
sql_hash | 6079808577596655075
plan_hash | -487722818968417375
queryid | -8984284243102644350
cost | 36.785
sample_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 900;
query_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= $1 AND t2.y > $2;
constants | 1000, 900
prep_const |
hint_str | Leading(("t1" "t2" )) HashJoin("t1" "t2") IndexScan("t2" "a_y_idx") SeqScan("t1")
explain_plan | Aggregate (cost=36.77..36.78 rows=1 width=8)
| Output: count(*)
| -> Hash Join (cost=11.28..36.52 rows=100 width=0)
| Hash Cond: (t1.x = t2.x)
| -> Seq Scan on public.a t1 (cost=0.00..20.50 rows=1000 width=4)
| Output: t1.x, t1.y
| Filter: (t1.y <= 1000)
| -> Hash (cost=10.03..10.03 rows=100 width=4)
| Output: t2.x
| Buckets: 1024 Batches: 1 Memory Usage: 12kB
| -> Index Scan using a_y_idx on public.a t2 (cost=0.28..10.03 rows=100 width=4)
| Output: t2.x
| Index Cond: (t2.y > 900)
| Query Identifier: -8984284243102644350
|
-[ RECORD 2 ]-+-----------------------------------------------------------------------------------------------------
dbid | 5
sql_hash | 6079808577596655075
plan_hash | 2719320099967191582
queryid | -8984284243102644350
cost | 18.997500000000002
sample_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 10 AND t2.y > 900;
query_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= $1 AND t2.y > $2;
constants | 10, 900
prep_const |
hint_str | Leading(("t2" "t1" )) HashJoin("t1" "t2") IndexScan("t2" "a_y_idx") IndexScan("t1" "a_y_idx")
explain_plan | Aggregate (cost=18.99..19.00 rows=1 width=8)
| Output: count(*)
| -> Hash Join (cost=8.85..18.98 rows=1 width=0)
| Hash Cond: (t2.x = t1.x)
| -> Index Scan using a_y_idx on public.a t2 (cost=0.28..10.03 rows=100 width=4)
| Output: t2.x, t2.y
| Index Cond: (t2.y > 900)
| -> Hash (cost=8.45..8.45 rows=10 width=4)
| Output: t1.x
| Buckets: 1024 Batches: 1 Memory Usage: 9kB
| -> Index Scan using a_y_idx on public.a t1 (cost=0.28..8.45 rows=10 width=4)
| Output: t1.x
| Index Cond: (t1.y <= 10)
| Query Identifier: -8984284243102644350
|
-- Disable the automatic capturing. This will not affect previously captured plans.
SET pgpro_multiplan.auto_capturing = 'off';
G.3.5.2. Approving a Plan #
You can approve any plan from the pgpro_multiplan_captured_queries view by using the pgpro_multiplan_captured_approve() function with the specified dbid, sql_hash, and plan_hash parameters.
-- Manually approve the plan with index scans
SELECT pgpro_multiplan_captured_approve(5, 6079808577596655075, 2719320099967191582);
pgpro_multiplan_captured_approve
----------------------------------
t
(1 row)
-- Or approve plans selected from the captured list
SELECT pgpro_multiplan_captured_approve(dbid, sql_hash, plan_hash)
FROM pgpro_multiplan_captured_queries
WHERE query_string like '%SELECT % FROM a t1, a t2%';
pgpro_multiplan_captured_approve
----------------------------------
t
(1 row)
-- Approved plans are automatically removed from the captured queries storage
SELECT count(*) FROM pgpro_multiplan_captured_queries;
count
-------
0
(1 row)
-- Approved plans are shown in the pgpro_multiplan_storage view
SELECT * FROM pgpro_multiplan_storage \gx
-[ RECORD 1 ]-+------------------------------------------------------------------------------------------------
dbid | 5
sql_hash | 6079808577596655075
const_hash | 0
plan_hash | -487722818968417375
valid | t
cost | 36.785
sample_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 900;
query_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= $1 AND t2.y > $2;
paramtypes |
query | <>
plan | <>
plan_type | baseline
hintstr | Leading(("t1" "t2" )) HashJoin("t1" "t2") IndexScan("t2" "a_y_idx") SeqScan("t1")
wildcards |
-[ RECORD 2 ]-+------------------------------------------------------------------------------------------------
dbid | 5
sql_hash | 6079808577596655075
const_hash | 0
plan_hash | 2719320099967191582
valid | t
cost | 18.997500000000002
sample_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 10 AND t2.y > 900;
query_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= $1 AND t2.y > $2;
paramtypes |
query | <>
plan | <>
plan_type | baseline
hintstr | Leading(("t2" "t1" )) HashJoin("t1" "t2") IndexScan("t2" "a_y_idx") IndexScan("t1" "a_y_idx")
wildcards |
G.3.5.3. Allowed Plan Example #
The following example illustrates the use of allowed plans.
-- Enable the auto_capturing parameter
SET pgpro_multiplan.mode = 'baseline'
SET pgpro_multiplan.auto_capturing = 'on';
-- Execute the query
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 900;
QUERY PLAN
--------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Hash Join (actual rows=100 loops=1)
Hash Cond: (t1.x = t2.x)
-> Seq Scan on a t1 (actual rows=1000 loops=1)
Filter: (y <= 1000)
-> Hash (actual rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 12kB
-> Index Scan using a_y_idx on a t2 (actual rows=100 loops=1)
Index Cond: (y > 900)
Planning Time: 0.543 ms
Execution Time: 0.688 ms
(16 rows)
-- And execute it again with different constants
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 10 AND t2.y > 900;
QUERY PLAN
--------------------------------------------------------------------------------
Aggregate (actual rows=1 loops=1)
-> Hash Join (actual rows=0 loops=1)
Hash Cond: (t2.x = t1.x)
-> Index Scan using a_y_idx on a t2 (actual rows=100 loops=1)
Index Cond: (y > 900)
-> Hash (actual rows=10 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Index Scan using a_y_idx on a t1 (actual rows=10 loops=1)
Index Cond: (y <= 10)
Planning Time: 0.495 ms
Execution Time: 0.252 ms
(16 rows)
-- Disable the automatic capturing
SET pgpro_multiplan.auto_capturing = 'off';
-- Approve all captured plans
SELECT pgpro_multiplan_captured_approve(dbid, sql_hash, plan_hash)
FROM pgpro_multiplan_captured_queries;
pgpro_multiplan_captured_approve
----------------------------------
t
t
(2 rows)
-- The plan does not change because it is one of the allowed ones
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 900;
QUERY PLAN
--------------------------------------------------------------------------------
Custom Scan (MultiplanScan) (actual rows=1 loops=1)
Plan is: baseline
SQL hash: 6079808577596655075
Const hash: 0
Plan hash: -487722818968417375
-> Aggregate (actual rows=1 loops=1)
-> Hash Join (actual rows=100 loops=1)
Hash Cond: (t1.x = t2.x)
-> Seq Scan on a t1 (actual rows=1000 loops=1)
Filter: (y <= 1000)
-> Hash (actual rows=100 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 12kB
-> Index Scan using a_y_idx on a t2 (actual rows=100 loops=1)
Index Cond: (y > 900)
Planning Time: 0.426 ms
Execution Time: 0.519 ms
(16 rows)
-- This plan would normally perform seqscan on both tables, but is currently the cheapest of the allowed set
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 1000 AND t2.y > 0;
QUERY PLAN
--------------------------------------------------------------------------------
Custom Scan (MultiplanScan) (actual rows=1 loops=1)
Plan is: baseline
SQL hash: 6079808577596655075
Const hash: 0
Plan hash: 2719320099967191582
-> Aggregate (actual rows=1 loops=1)
-> Hash Join (actual rows=1000 loops=1)
Hash Cond: (t2.x = t1.x)
-> Index Scan using a_y_idx on a t2 (actual rows=1000 loops=1)
Index Cond: (y > $2)
-> Hash (actual rows=1000 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 44kB
-> Index Scan using a_y_idx on a t1 (actual rows=1000 loops=1)
Index Cond: (y <= $1)
Planning Time: 2.473 ms
Execution Time: 1.859 ms
(16 rows)
G.3.6. Frozen Plan Backups #
The pgpro_multiplan extension allows you to create a backup of frozen plans and then restore these plans into the current database. This can be useful to transfer plans between databases or server instances.
To back up frozen plans from a specific database, use the pgpro_multiplan_storage view like this:
CREATE TABLE storage_copy AS SELECT s.* FROM pgpro_multiplan_storage s JOIN pg_database d ON s.dbid = d.oid WHERE d.datname = 'db_name';
To restore frozen plans from a backup, call the pgpro_multiplan_restore() function:
SELECT s.query_string, res.sql_hash IS NOT NULL AS success FROM storage_copy s, LATERAL pgpro_multiplan_restore(s.query_string, s.hintstr, s.paramtypes, s.plan_type) res;
Note
Plans can be restored only when the pg_hint_plan extension is active, see the Compatibility with Other Extensions section.
Plans are always restored into the current database. To restore plans into another database, connect to it first. Thus, it is recommended to create a backup with plans only from one required database as for db_name in the examples in this section. If you need to transfer plans for multiple databases, create separate backups for them, connect to each target database sequentially one by one, and restore the corresponding plans from backups.
G.3.6.1. Limitations #
When you back up and restore plans, take into account the following limitations:
Only frozen plans can be restored.
Frozen plans of the
templatetype cannot be restored. Onlyserializedandhintsetplans are supported.If you back up plans from multiple databases and those databases contain different frozen plans for identical queries, only the first conflicting plan will be restored.
Only plans for valid queries can be restored, which means that all relations used in the query must exist in the current database.
G.3.6.2. Use Cases #
This section describes how to back up and restore frozen plans in different popular scenarios.
G.3.6.2.1. Upgrading a Server Version #
Follow the steps below to save frozen plans when upgrading a server from an older version that has an incompatible data storage.
Back up frozen plans before upgrade.
CREATE TABLE storage_copy AS SELECT s.* FROM pgpro_multiplan_storage s JOIN pg_database d ON s.dbid = d.oid WHERE d.datname = 'db_name';
Upgrade the server.
Restore frozen plans.
SELECT pgpro_multiplan_restore(query_string, hintstr, paramtypes, plan_type) FROM storage_copy;
G.3.6.2.2. Transferring Plans Between Server Instances #
To transfer frozen plans between two servers, do the following:
Connect to the source server.
Back up frozen plans to a table.
CREATE TABLE storage_copy AS SELECT s.* FROM pgpro_multiplan_storage s JOIN pg_database d ON s.dbid = d.oid WHERE d.datname = 'db_name';
Use the pg_dump utility to dump the table to a file.
$ pg_dump --table storage_copy -Ft postgres > storage_copy.tar
Connect to the target server and connect to the required database.
Move the created dump file to the target file system.
Use the pg_restore utility to restore the table with frozen plans from the dump file.
$ pg_restore --dbname postgres -Ft storage_copy.tar
Restore frozen plans.
SELECT pgpro_multiplan_restore(query_string, hintstr, paramtypes, plan_type) FROM storage_copy; DROP TABLE storage_copy;
G.3.6.2.3. Transferring Plans From the Sandbox to the Regular Storage #
To transfer frozen plans from the sandbox to the regular storage, complete the following steps:
Set the pgpro_multiplan.sandbox parameter to
onand back up frozen plans from the sandbox.SET pgpro_multiplan.sandbox = ON; CREATE TABLE storage_copy AS SELECT s.* FROM pgpro_multiplan_storage s JOIN pg_database d ON s.dbid = d.oid WHERE d.datname = 'db_name';
Set the
pgpro_multiplan.sandboxparameter tooffand restore frozen plans into the regular storage.SET pgpro_multiplan.sandbox = OFF; SELECT pgpro_multiplan_restore(query_string, hintstr, paramtypes, plan_type) FROM storage_copy;
G.3.6.2.4. Transferring Plans Between Databases #
To transfer frozen plans from one database to another, connect to the target database and restore plans as shown below.
SELECT pgpro_multiplan_restore(s.query_string, s.hintstr, s.paramtypes, s.plan_type) FROM pgpro_multiplan_storage s JOIN pg_database d ON s.dbid = d.oid WHERE d.datname = 'db_name';
Here db_name is the name of the database from which you want to transfer plans.
G.3.6.2.5. Example of Transferring Plans #
This example demonstrates how to transfer plans from one server instance to another.
-- Connect to the source server
psql (17.4)
Type "help" for help.
-- In this example, 1000 plans are stored in the pgpro_multiplan_storage view
postgres=# select count(*) from pgpro_multiplan_storage;
count
-------
1000
(1 row)
-- Copy frozen plans from the postgres database to a table
postgres=# CREATE TABLE storage_copy AS SELECT s.*
FROM pgpro_multiplan_storage s
JOIN pg_database d ON s.dbid = d.oid
WHERE d.datname = 'postgres';
-- Dump the table to an archive file
$ pg_dump --table storage_copy -Ft postgres > storage_copy.tar
-- Close the connection to the source server
-- Connect to the target server
./psql postgres
psql (16.8)
Type "help" for help.
-- Create the pgpro_multiplan extension and enable it
postgres=# create extension pgpro_multiplan;
CREATE EXTENSION
SET pgpro_multiplan.mode = 'frozen';
SET
-- This server does not contain frozen plans
postgres=# select count(*) from pgpro_multiplan_storage;
count
-------
0
(1 row)
-- Move the dump file with frozen plans to the target file system
-- Restore the table with frozen plans from the dump
$ pg_restore --dbname postgres -Ft storage_copy.tar
-- Restore frozen plans from the table using the pgpro_multiplan_restore function
postgres=# SELECT pgpro_multiplan_restore(query_string, hintstr, paramtypes, plan_type)
FROM storage_copy;
pgpro_multiplan_restore
----------------------------------
(8436876698844323073,871432885)
(8436876698844323073,573678316)
(8436876698844323073,1999378082)
(8436876698844323073,1681603536)
(8436876698844323073,3959620774)
...
(8436876698844323073,1263226437)
(8436876698844323073,4053700861)
(8436876698844323073,2418458596)
(8436876698844323073,413896030)
(1000 rows)
-- The function restores 1000 frozen plans. The result is shown as pairs of sql_hash and const_hash
-- Frozen queries were identical and differed only in constants, so sql_hash is the same for all plans
-- Drop the table used to restore plans
postgres=# DROP TABLE storage_copy;
DROP TABLE
-- The target server now also stores 1000 frozen plans
postgres=# select count(*) from pgpro_multiplan_storage;
count
-------
1000
(1 row)
-- Disable pgpro_multiplan and run the query
postgres=# SET pgpro_multiplan.mode = '';
SET
postgres=# EXPLAIN (COSTS OFF) SELECT * FROM a WHERE x > 10;
QUERY PLAN
--------------------
Seq Scan on a
Filter: (x > 10)
(2 rows)
-- Enable pgpro_multiplan and run the same query once again
-- One of the restored plans is now used
postgres=# SET pgpro_multiplan.mode = 'frozen';
SET
postgres=# EXPLAIN (COSTS OFF) SELECT * FROM a WHERE x > 10;
QUERY PLAN
-------------------------------------
Custom Scan (MultiplanScan)
Plan is: frozen, serialized
SQL hash: 8436876698844323073
Const hash: 2295408638
Plan hash: 0
-> Index Scan using a_x_idx on a
Index Cond: (x > 10)
(7 rows)
G.3.7. Compatibility with Other Extensions #
To ensure compatibility of pgpro_multiplan with other enabled extensions, specify the library names in the shared_preload_libraries variable in the postgresql.conf file in the specific order:
pg_hint_plan: pgpro_multiplan must be loaded after pg_hint_plan.
shared_preload_libraries = 'pg_hint_plan, pgpro_multiplan'
aqo: pgpro_multiplan must be loaded before aqo.
shared_preload_libraries = 'pgpro_multiplan, aqo'
pgpro_stats: pgpro_multiplan must be loaded after pgpro_stats.
shared_preload_libraries = 'pgpro_stats, pgpro_multiplan'
G.3.8. Query Identification #
A query in the current database is identified by a combination of sql_hash and const_hash.
sql_hash is a hash generated based on the parse tree, ignoring parameters and constants. Field and table aliases are not ignored. Therefore, the same query with different aliases will have different sql_hash values.
const_hash is a hash generated based on all constants involved in the query. Constants with the same value but different types, such as 1 and '1', will produce different hash values.
G.3.9. Automatic Type Casting #
pgpro_multiplan automatically attempts to cast the types of constants involved in the query to match the parameter types of the query for which a plan is frozen or added to a set of allowed plans. If type casting is not possible, the plan is ignored.
SELECT sql_hash, const_hash
FROM pgpro_multiplan_register_query('SELECT count(*) FROM a
WHERE x = $1', 'int');
-- Type casting is possible
EXPLAIN SELECT count(*) FROM a WHERE x = '1';
QUERY PLAN
-------------------------------------------------------------
Custom Scan (MultiplanScan) (cost=1.38..1.39 rows=1 width=8)
Plan is: tracked
SQL hash: -5166001356546372387
Const hash: 0
Plan hash: 0
-> Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = $1)
-- Type casting is possible
EXPLAIN SELECT count(*) FROM a WHERE x = 1::bigint;
QUERY PLAN
-------------------------------------------------------------
Custom Scan (MultiplanScan) (cost=1.38..1.39 rows=1 width=8)
Plan is: tracked
SQL hash: -5166001356546372387
Const hash: 0
Plan hash: 0
-> Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = $1)
-- Type casting is impossible
EXPLAIN SELECT count(*) FROM a WHERE x = 1111111111111;
QUERY PLAN
-------------------------------------------------------
Aggregate (cost=1.38..1.39 rows=1 width=8)
-> Seq Scan on a (cost=0.00..1.38 rows=1 width=0)
Filter: (x = '1111111111111'::bigint)
G.3.10. Plan Usage Statistics #
To collect statistics about the usage of frozen and allowed plans, specify the statistics value in the pgpro_multiplan.mode parameter. These statistics are stored in the pgpro_multiplan_stats view. The pgpro_multiplan.max_stats parameter specifies the maximum number of collected statistics values. When this limit is reached, further statistics will be discarded. If a plan is changed, the statistics of the plan's usage are reset and recalculated using the new plan_hash.
For more detailed planning and execution statistics, you can use the pgpro_stats extension (see the Compatibility with Other Extensions section). These statistics can be accessed using the pgpro_stats_statements view.
You can join information from the pgpro_multiplan_stats and pgpro_stats_statements views by the planid field.
The following example demonstrates how to collect and view statistics. It uses the query and frozen plan from the Frozen Plan Example.
-- Enable collecting statistics
SET pgpro_multiplan.mode = 'frozen, statistics';
-- Execute the query
SELECT count(*) FROM a
WHERE x = 1 OR (x > 11 AND x < 22) OR x = 22;
count
-------
12
(1 row)
-- Now you can see statistics of the plan usage
SELECT * FROM pgpro_multiplan_stats;
dbid | sql_hash | const_hash | plan_hash | planid | counter
------+---------------------+------------+-----------+---------------------+---------
5 | 6062491547151210914 | 2413041345 | 0 | 3549961214127427294 | 1
(1 row)
G.3.11. Integration with AQE #
The pgpro_multiplan extension can work in conjunction with adaptive query execution (AQE) providing more flexible features for managing query execution plans.
AQE attempts to reoptimize a query if a specific trigger fires during query execution indicating that it is non-optimal. To enable AQE, use the aqe_enable configuration parameter.
The pgpro_multiplan.aqe_mode configuration parameter specifies a comma-separated list of enabled AQE-related features.
G.3.11.1. Real-Time Plan Management #
Real-time plan management adds plans produced by AQE to the list of allowed plans automatically.
To enable this functionality, do the following:
Set the aqe_enable parameter to
onto activate AQE.Specify one or more required AQE triggers using the aqe_sql_execution_time_trigger, aqe_rows_underestimation_rate_trigger, and aqe_backend_memory_used_trigger parameters.
Specify the
baselinevalue in the pgpro_multiplan.mode parameter to enable the use of allowed plans.Specify the
auto_approve_plansvalue in the pgpro_multiplan.aqe_mode parameter.
The following example demonstrates how to use real-time plan management.
INSERT INTO a SELECT x, x AS y FROM generate_series(1001,2000) x;
-- Enable AQE and its node tuples underestimation trigger
SET aqe_enable = 'on';
SET aqe_rows_underestimation_rate_trigger = 2;
-- Configure pgpro_multiplan modes
SET pgpro_multiplan.mode = 'baseline';
SET pgpro_multiplan.aqe_mode = 'auto_approve_plans';
-- Execute a query
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 2000 AND t2.y > 900;
count
-------
1100
(1 row)
-- The query was reoptimized by AQE according to its trigger
-- The query execution plan was saved to a baseline (a list of allowed plans)
-- Now you can see the plan using the corresponding view
SELECT * FROM pgpro_multiplan_storage \gx
-[ RECORD 1 ]-+------------------------------------------------------------------------------------
dbid | 16384
sql_hash | 771426262442742808
const_hash | 0
plan_hash | -487722818968417375
valid | t
cost | 75.78750000000001
sample_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 2000 AND t2.y > 900;
query_string | SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= $1 AND t2.y > $2;
paramtypes |
query | <>
plan_type | baseline
plan | <>
hintstr | Leading(("t1" "t2" )) HashJoin("t1" "t2") IndexScan("t2" "a_y_idx") SeqScan("t1")
wildcards |
-- Disable AQE
RESET aqe_enable;
RESET aqe_rows_underestimation_rate_trigger;
-- Execute the same query and see that the previously saved plan is used
explain analyze
SELECT count(*) FROM a t1, a t2 WHERE t1.x = t2.x AND t1.y <= 2000 AND t2.y > 900;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Custom Scan (MultiplanScan) (cost=52.03..52.04 rows=1 width=8) (actual time=2.148..2.150 rows=1 loops=1)
Plan is: baseline
SQL hash: 771426262442742808
Const hash: 0
Plan hash: -487722818968417375
-> Aggregate (cost=52.03..52.04 rows=1 width=8) (actual time=2.148..2.149 rows=1 loops=1)
-> Hash Join (cost=13.78..51.65 rows=150 width=0) (actual time=1.390..2.051 rows=1100 loops=1)
Hash Cond: (t1.x = t2.x)
-> Seq Scan on a t1 (cost=0.00..30.75 rows=1500 width=4) (actual time=0.028..0.597 rows=2000 loops=1)
Filter: (y <= 2000)
-> Hash (cost=11.90..11.90 rows=150 width=4) (actual time=0.993..0.993 rows=1100 loops=1)
Buckets: 2048 (originally 1024) Batches: 1 (originally 1) Memory Usage: 55kB
-> Index Scan using a_y_idx on a t2 (cost=0.28..11.90 rows=150 width=4) (actual time=0.026..0.695 rows=1100 loops=1)
Index Cond: (y > 900)
Planning Time: 0.460 ms
Execution Time: 2.194 ms
(16 rows)
G.3.11.2. Individual Trigger Values #
The pgpro_multiplan extension allows you to override and adjust global AQE trigger values for individual queries. Global triggers are specified in the aqe_sql_execution_time_trigger, aqe_rows_underestimation_rate_trigger, and aqe_backend_memory_used_trigger configuration parameters.
To use this functionality, do the following:
Set the aqe_enable parameter to
onto activate AQE.Specify the
individual_triggersvalue in the pgpro_multiplan.aqe_mode parameter.Call the set_aqe_trigger function for each query whose triggers you want to override.
All individual trigger values are shown in the aqe_triggers view. The pgpro_multiplan.aqe_max_items parameter specifies the maximum number of stored trigger values.
G.3.11.3. AQE Statistics #
pgpro_multiplan can collect AQE statistics for all statements considered feasible for reoptimization. These statistics are stored in shared memory until a server shutdown and are not replicated.
Perform the following steps to enable statistics collection:
Set the aqe_enable parameter to
onto activate AQE.Specify the
statisticsvalue in the pgpro_multiplan.aqe_mode parameter.Enable query ID computation using the compute_query_id parameter.
All statistics values are shown in the aqe_stats view. The pgpro_multiplan.aqe_max_stats parameter specifies the maximum number of collected statistics values. Further statistics are discarded.
G.3.12. Global Prepared Statements #
By default, prepared statements are available only within the current database session. These statements can be accessed using the system pg_prepared_statements view. When the session ends, its prepared statements are released and cannot be used again.
The pgpro_multiplan extension supports global prepared statements that are shared between multiple or all sessions within the current server. To enable this functionality, set the pgpro_multiplan.global_prepared_statements parameter to on in one of the following ways:
at server start (in the
postgresql.conffile) to activate the functionality for all sessionsfor individual required sessions using the
SETcommand
When a prepared statement is created in such a session, it is saved to a global storage and then can be used in all active sessions in parallel. These global prepared statements can be accessed using the pgpro_global_prepared_statements view. When a session ends, prepared statements created in it are not removed and remain available for other sessions. But if a prepared statement is deallocated explicitly, it is removed from the global storage.
The example below demonstrates how to use global prepared statements in two sessions.
-- Open the first session and create a prepared statement named "p"
PREPARE p (int,int) as SELECT $1+$2 as plus;
-- Execute the created prepared statement in the same session
EXECUTE p (1,2);
plus
------
3
(1 row)
-- Open the second session and try to create a prepared statement with the same name
-- The error occurs since this statement already exists
PREPARE p (int,int) as SELECT $1+$2 as plus;
ERROR: shared prepared statement "p" already exists
-- Execute the prepared statement in the second session
EXECUTE p (1,2);
plus
------
3
(1 row)
-- Deallocate the prepared statement in the second session
DEALLOCATE p;
-- Try to execute this statement in the first session
-- The error occurs since this statement was released in the second session
EXECUTE p (1,2);
ERROR: prepared statement "p" does not exist
You can also set the pgpro_multiplan.global_prepared_statements_allow_duplicate parameter to on to avoid errors on attempts to create prepared statements that already exist as in the example above. However, if you try to create a prepared statement with the same name but another query, the error occurs anyway.
G.3.12.1. Considerations and Limitations #
Take into account the following specifics and limitations when using global prepared statements:
Global prepared statements are available only within a single server and cannot be shared between multiple servers in a cluster.
The global storage contains only prepared statements created in a session after the
pgpro_multiplan.global_prepared_statementsparameter was set toon. Even if a prepared statement was created earlier and is available in the local systempg_prepared_statementsview, it is not added to thepgpro_global_prepared_statementsview. When trying to execute such a statement, an error occurs and the statement is removed from the local storage.For correct execution, all relations referenced in a prepared statement must exist in all sessions. Thus, prepared statements should not rely on temporary tables or any other objects that are not supported by WAL replication.
G.3.13. Views #
G.3.13.1. The pgpro_multiplan_storage View #
The pgpro_multiplan_storage view provides detailed information about all frozen and allowed plans. The columns of the view are shown in Table G.4.
Table G.4. pgpro_multiplan_storage Columns
| Name | Type | Description |
|---|---|---|
dbid | oid | ID of the database where the statement is executed |
sql_hash | bigint | Internal query ID |
const_hash | bigint | Hash of non-parameterized constants |
plan_hash | bigint | Internal ID of the allowed plan, 0 for frozen plans |
valid | boolean | FALSE if the plan was invalidated the last time it was used |
cost | float | Cost of the allowed plan, 0 for frozen plans |
sample_string | text | Non-parameterized query with constants for which the plan was frozen or added to a set of allowed plans |
query_string | text | Parameterized query for which the plan was frozen or added to a set of allowed plans |
paramtypes | regtype[] | Array with parameter types used in the query |
query | text | Internal representation of the query |
plan | text | Internal representation of the plan |
plan_type | text | Plan type. For frozen plans: serialized, hintset, or template. For allowed plans: baseline |
hintstr | text | Set of hints formed based on the plan |
wildcards | text | Regular expression used for the template frozen plan, NULL for other plan types |
G.3.13.2. The pgpro_multiplan_local_cache View #
The pgpro_multiplan_local_cache view provides detailed information about registered and frozen statements in the local cache. The columns of the view are shown in Table G.5.
Table G.5. pgpro_multiplan_local_cache Columns
| Name | Type | Description |
|---|---|---|
sql_hash | bigint | Internal query ID |
const_hash | bigint | Hash of non-parameterized constants |
fs_is_frozen | boolean | TRUE if the statement is frozen |
fs_is_valid | boolean | TRUE if the statement is valid |
ps_is_valid | boolean | TRUE if the statement should be revalidated |
query_string | text | Query registered by the pgpro_multiplan_register_query function |
query | text | Internal representation of the query |
paramtypes | regtype[] | Array with parameter types used in the query |
hintstr | text | Set of hints formed based on the frozen plan |
G.3.13.3. The pgpro_multiplan_captured_queries View #
The pgpro_multiplan_captured_queries view provides detailed information about all queries captured in sessions. The columns of the view are shown in Table G.6.
Table G.6. pgpro_multiplan_captured_queries Columns
| Name | Type | Description |
|---|---|---|
dbid | oid | ID of the database where the statement is executed |
sql_hash | bigint | Internal query ID |
queryid | bigint | Standard query ID |
plan_hash | bigint | Internal plan ID |
planid | bigint | Plan ID compatible with the pgpro_stats extension |
cost | float | Plan cost |
sample_string | text | Last used non-parameterized query with constants |
query_string | text | Last used parameterized query |
constants | text | Set of constants in the query |
prep_consts | text | Set of constants used to EXECUTE a prepared statement |
hintstr | text | Set of hints formed based on the plan |
explain_plan | text | Plan shown by the EXPLAIN command |
G.3.13.4. The pgpro_multiplan_stats View #
The pgpro_multiplan_stats view provides statistics about the usage of frozen and allowed plans. The columns of the view are shown in Table G.7.
Table G.7. pgpro_multiplan_stats Columns
| Name | Type | Description |
|---|---|---|
dbid | oid | ID of the database where the statement is executed |
sql_hash | bigint | Internal query ID |
plan_hash | bigint | Internal plan ID |
planid | bigint | Plan ID compatible with the pgpro_stats extension |
counter | bigint | Number of times the plan was used |
G.3.13.5. The aqe_triggers View #
The aqe_triggers view provides information about individual AQE trigger values. The columns of the view are shown in Table G.8.
Table G.8. aqe_triggers Columns
| Name | Type | Description |
|---|---|---|
dbid | oid | ID of the database where the statement is executed |
sql_hash | bigint | Internal query ID |
query_string | text | Parameterized query |
execution_time | int | Value for the query execution time trigger, in milliseconds. NULL if the global trigger value is used |
memory | int | Value for the backend memory consumption trigger. NULL if the global trigger value is used |
underestimation_rate | double | Factor for the processed number of node tuples trigger. NULL if the global trigger value is used |
G.3.13.6. The aqe_stats View #
The aqe_stats view provides cumulative statistics about AQE reoptimizations. This view stores one row per each combination of the database ID, query, and execution plan. The columns of the view are shown in Table G.9.
Table G.9. aqe_stats Columns
| Name | Type | Description |
|---|---|---|
dbid | oid | ID of the database where the statement is executed |
sql_hash | bigint | Internal query ID |
planid | bigint | ID of the query execution plan |
query | text | Internal representation of the query |
last_updated | timestamp with time zone | Timestamp of the last statistics update |
exec_num | bigint | Number of query executions |
min_attempts | integer | Minimum number of times the query was reoptimized |
max_attempts | integer | Maximum number of times the query was reoptimized |
total_attempts | integer | Total number of times the query was reoptimized |
reason_repeated_plan | bigint | Number of times AQE was disabled because a repeated execution plan was generated |
reason_no_data | bigint | Number of times AQE was disabled because no new information was gathered during execution |
reason_max_reruns | bigint | Number of times AQE was disabled because the maximum number of reruns was reached |
reason_external | bigint | Number of times AQE was disabled by an extension, such as pgpro_multiplan |
reruns_forced | bigint | Total number of reoptimizations caused by the manual trigger |
reruns_time | bigint | Total number of reoptimizations caused by the query execution time trigger |
reruns_underestimation | bigint | Total number of reoptimizations caused by the processed number of node tuples trigger |
reruns_memory | bigint | Total number of reoptimizations caused by the backend memory trigger |
min_planning_time | double precision | Minimum time spent planning, in milliseconds |
max_planning_time | double precision | Maximum time spent planning, in milliseconds |
mean_planning_time | double precision | Mean time spent planning, in milliseconds |
stddev_planning_time | double precision | Population standard deviation of time spent planning, in milliseconds |
min_exec_time | double precision | Minimum time spent on query execution, in milliseconds |
max_exec_time | double precision | Maximum time spent on query execution, in milliseconds |
mean_exec_time | double precision | Mean time spent on query execution, in milliseconds |
stddev_exec_time | double precision | Population standard deviation of time spent on query execution, in milliseconds |
G.3.13.7. The pgpro_global_prepared_statements View #
The pgpro_global_prepared_statements view provides detailed information about all global prepared statements. The columns of the view are shown in Table G.10.
Table G.10. pgpro_global_prepared_statements Columns
| Name | Type | Description |
|---|---|---|
session_id | bytea | ID of the session where the prepared statement was created |
name | varchar | Name of the prepared statement |
prepare_time | timestamp | Initial timestamp at which the prepared statement was created. It is not updated if the same prepared statement is re-created |
from_sql | bool | true if the prepared statement was created using the PREPARE command, false otherwise |
param_num | int4 | Number of parameters used in the prepared statement |
param_types | regtype[] | Array with parameter types used in the prepared statement |
statement | text | Query used to create the prepared statement |
G.3.14. Functions #
Only superusers can call the functions listed below.
-
pgpro_multiplan_register_query(query_stringtext) returns record
pgpro_multiplan_register_query(#query_stringtext,VARIADICregtype[]) returns record Saves the query described in the
query_stringparameter in the local cache that can be accessed using the pgpro_multiplan_local_cache view. Returns the unique pair ofsql_hashandconst_hash.-
pgpro_multiplan_unregister_query() returns bool# Removes the query that was registered but not frozen from the
pgpro_multiplan_local_cacheview. Returnstrueif there are no errors.-
pgpro_multiplan_freeze(#plan_typetext) returns bool Freezes the last used plan for the query and saves it to the permanent pgpro_multiplan storage that can be accessed using the pgpro_multiplan_storage view. The allowed values of the optional
plan_typeargument areserialized,hintset, andtemplate.serializedis used by default. For details about plan types, see Supported Modes and Plan Types. Returnstrueif the plan was frozen successfully.-
pgpro_multiplan_unfreeze(#sql_hashbigint,const_hashbigint) returns bool Removes the specified plan from the permanent storage but keeps the query registered in the local cache. Returns
trueif there are no errors.-
pgpro_multiplan_remove(#sql_hashbigint,const_hashbigint) returns bool Removes the frozen statement with the specified
sql_hashandconst_hashparameters. Operates aspgpro_multiplan_unfreezeandpgpro_multiplan_unregister_querycalled sequentially. Returnstrueif there are no errors.-
pgpro_multiplan_reset(#dbidoid) returns bigint Removes all records from the
pgpro_multiplan_storageview for the specified database. Omitdbidto remove the data collected by pgpro_multiplan for the current database. Setdbidto NULL to reset data for all databases. Returns the number of removed records.-
pgpro_multiplan_reload_frozen_plancache() returns bool# Drops all frozen plans and reloads them in the
pgpro_multiplan_storageview. It also drops statements that have been registered but not frozen. Returnstrueif there are no errors.-
pgpro_multiplan_stats() returns table# Returns statistics of the plan usage from the pgpro_multiplan_stats view.
-
pgpro_multiplan_registered_query(#sql_hashbigint,const_hashbigint) returns table Returns the registered query with the specified
sql_hashandconst_hashparameters even if it is not frozen, for debugging purposes only. This works if the query is registered in the current backend or frozen in the current database.-
pgpro_multiplan_captured_approve(#dbidoid,sql_hashbigint,plan_hashbigint) returns bool Adds the specified plan for the captured query to a baseline (a set of allowed plans) and saves it to the
pgpro_multiplan_storageview. Returnstrueif the plan was added successfully.-
pgpro_multiplan_remove_baseline(#dbidoid,sql_hashbigint,plan_hashbigint) returns bool Removes the specified allowed plan from the permanent storage. Returns
trueif the plan was removed successfully.-
pgpro_multiplan_remove_template(#dbidoid,sql_hashbigint,plan_hashbigint) returns bool Removes the specified
templateplan from the permanent storage. Returnstrueif the plan was removed successfully.-
pgpro_multiplan_set_plan_type(#sql_hashbigint,const_hashbigint,plan_typetext) returns bool Sets the type of the query plan for the frozen statement. The allowed values of the
plan_typeargument areserialized,hintset, andtemplate. To be able to use the query plan of thehintsetortemplatetype, the pg_hint_plan module must be loaded. Returnstrueif the plan type was changed successfully.-
pgpro_multiplan_hintset_update(#sql_hashbigint,const_hashbigint,hintsettext) returns bool Replaces the generated hint set for the
hintsetfrozen plan or the allowed plan with the specified set of custom hints. A string with custom hints should not be enclosed in the special comment used in pg_hint_plan, that is it should not start with/*+and end with*/. Returnstrueif the hint set was changed successfully.-
pgpro_multiplan_template_hintset_update(#sql_hashbigint,const_hashbigint,hintsettext) returns bool Replaces the generated hint set for the
templatefrozen plan with the specified set of custom hints. A string with custom hints should not be enclosed in the special comment used in pg_hint_plan, that is it should not start with/*+and end with*/. Returnstrueif the hint set was changed successfully.-
pgpro_multiplan_captured_clean() returns bigint# Removes all records from the pgpro_multiplan_captured_queries view. Returns the number of removed records.
-
get_sql_hash(#query_stringtext) returns bigint Returns the internal ID (
sql_hash) for the specified query.-
set_aqe_trigger(trigger_nametext,trigger_valint,query_stringtext) returns bool
set_aqe_trigger(#trigger_nametext,trigger_valdouble precision,query_stringtext) returns bool Sets or resets the individual value of the AQE trigger for the specified query. The individual trigger value overrides the global trigger value specified in the AQE configuration parameter. For this feature to work, ensure that the
individual_triggersvalue is specified in the pgpro_multiplan.aqe_mode parameter.This function has the following arguments:
trigger_name: The trigger name. The following values are allowed:execution_time: The query execution time trigger. Corresponds to the aqe_sql_execution_time_trigger configuration parameter.memory: The backend memory consumption trigger. Corresponds to the aqe_backend_memory_used_trigger configuration parameter.underestimation_rate: The processed number of node tuples trigger. Corresponds to the aqe_rows_underestimation_rate_trigger configuration parameter.
trigger_val: The trigger value. Forexecution_timeandmemorytriggers, specify integer values. Forunderestimation_rate, you can define double precision values. To reset the individual trigger value, specifyNULLor negative value less than -1.query_string: The query text.
This function returns
trueif there are no errors.-
aqe_triggers_reset(#dbidoid) returns bigint Removes all records from the
aqe_triggersview for the specified database. To clean theaqe_triggersview for the current database, omitdbid. To remove records from this view for all databases, setdbidtoNULL. Returns the number of removed records.-
aqe_stats_reset(#dbidoid) returns bigint Removes all records from the
aqe_statsview for the specified database. To clean theaqe_statsview for the current database, omitdbid. To remove records from this view for all databases, setdbidtoNULL. Returns the number of removed records.-
pgpro_multiplan_restore(#query_stringtext,hintstrtexttext,paramtypesregtype[],plan_typetext) returns record Restores the frozen plan for the specified query into the current database.
This function has the following arguments:
query_string: The query with$parameters (same as innPREPARE) for which to restore the frozen plan based on a set of hints.statement_nameAShintstr: A set of hints supported by the pg_hint_plan extension. If this argument is set toNULLor empty string, the standard plan will be used.parameter_type: An array with parameter types used in the query. If this argument is set toNULL, parameter types should be determined automatically.plan_type: The plan type. Allowed values areserializedandhintset. Thetemplateplan is not supported.
The function returns the unique pair of
sql_hashandconst_hashif the plan was restored successfully. Otherwise, it returnsNULL.-
pgpro_global_prepared_statements_reset() returns int# Removes all global prepared statements and returns the number of removed records.
-
pgpro_global_prepared_statements_reset(#session_idbytea) returns int Removes global prepared statements created in the specified session and returns the number of removed records.
-
pgpro_global_prepared_statements_session() returns bytea# Returns the ID of the current session.
-
pgpro_global_prepared_statements_session(#session_idbytea) Sets the specified ID for the current session and returns the previous ID.
G.3.15. Configuration Parameters #
-
pgpro_multiplan.mode(string) # A comma-separated list of enabled pgpro_multiplan modes. The following values are available:
frozen: Enables the use ofserializedandhintsetfrozen plans.wildcards: Enables the use oftemplatefrozen plans.baseline: Enables the use of allowed plans.statistics: Enables collecting statistics about the plan usage. These statistics are stored in the pgpro_multiplan_stats view. This value can be specified only together with one or more plan types.
SET pgpro_multiplan.mode = 'frozen, wildcards, baseline, statistics';
For details about plan types, see Supported Modes and Plan Types. For more information about collecting statistics, refer to Statistics.
By default, the
pgpro_multiplan.modeparameter is set to an empty string, which means that all plan modes are disabled. Only superusers can change this setting.-
pgpro_multiplan.aqe_mode(string) # A comma-separated list of enabled AQE-related features. The following values are available:
auto_approve_plans: Enables real-time plan management.individual_triggers: Enables you to specify individual AQE trigger values.statistics: Enables collecting AQE statistics.
SET pgpro_multiplan.aqe_mode = 'auto_approve_plans, individual_triggers, statistics';
For these features to work, ensure that AQE is enabled using the aqe_enable configuration parameter.
By default, the
pgpro_multiplan.aqe_modeparameter is set to an empty string. Only superusers can change this setting.-
pgpro_multiplan.max_stats(integer) # Sets the maximum number of statistics values that can be stored in the
pgpro_multiplan_statsview. Further statistics will be discarded. The default value is 5000. This parameter can only be set at server start.-
pgpro_multiplan.max_items(integer) # Sets the maximum number of entries pgpro_multiplan can operate with. The default value is 100. This parameter can only be set at server start.
-
pgpro_multiplan.auto_tracking(boolean) # Enables pgpro_multiplan to normalize and register queries executed using the
EXPLAINcommand automatically. The default value isoff. Only superusers can change this setting.-
pgpro_multiplan.max_local_cache_size(integer) # Sets the maximum size of local cache, in kB. The default value is zero, which means no limit. Only superusers can change this setting.
-
pgpro_multiplan.wal_rw(boolean) # Enables physical replication of pgpro_multiplan data. When set to
offon the primary, no data is transferred from it to a standby. When set tooffon a standby, any data transferred from the primary is ignored. The default value isoff.This parameter can only be set at server start.-
pgpro_multiplan.auto_capturing(boolean) # Enables the automatic query capture in pgpro_multiplan. Setting this configuration parameter to
onallows you to see the queries with constants in the text form as well as parameterized queries in the pgpro_multiplan_captured_queries view. Also, all plans for each query are shown. Information about executed queries is stored until the server restart. The default value isoff. Only superusers can change this setting.-
pgpro_multiplan.max_captured_items(integer) # Sets the maximum number of queries pgpro_multiplan can capture. The default value is 1000. This parameter can only be set at server start.
-
pgpro_multiplan.sandbox(boolean) # Enables reserving a separate area in shared memory to be used by a primary or standby node, which allows testing and analyzing queries with the existing data set without affecting the node operation. If set to
onon the standby, pgpro_multiplan freezes plans only on this node and stores them in the “sandbox”, an alternative plan storage. If enabled on the primary, the extension uses the separate shared memory area that is not replicated to the standby. Changing the parameter value resets the pgpro_multiplan cache. The default value isoff. Only superusers can change this setting.-
pgpro_multiplan.wildcards(string) # A
POSIXregular expression used fortemplateplans to check matching of table names referenced in queries. Thepgpro_multiplan.wildcardsvalue is frozen along with the corresponding query. The default value is.*that means matching for any table name.-
pgpro_multiplan.aqe_max_items(integer) # Sets the maximum number of stored individual AQE trigger values. The default value is
100. This parameter can only be set at server start.-
pgpro_multiplan.aqe_max_stats(integer) # Sets the maximum number of collected AQE statistics values. Further statistics are discarded. The default value is
5000. This parameter can only be set at server start.-
pgpro_multiplan.global_prepared_statements(boolean) # Enables storing and sharing global prepared statements for multiple sessions within the current server. The default value is
off. Only superusers can change this setting.-
pgpro_multiplan.global_prepared_statements_allow_duplicate(boolean) # Enables creation of identical global prepared statements without raising errors. The default value is
off. Only superusers can change this setting.