All Products
Search
Document Center

PolarDB:Statement outline

Last Updated:Mar 28, 2026

When you can't modify SQL in your application—because queries are auto-generated by middleware or a code release takes too long—use statement outline (OUTLINE) to inject optimizer hints at the database layer and stabilize execution plans without touching application code.

How it works

OUTLINE associates a hint with a class of SQL statements identified by a SQL_ID. When a query matches the SQL_ID, the database applies the bound hints before optimization, overriding any hints embedded in the original SQL.

All OUTLINE operations go through the hint_plan schema:

OperationFunction or view
Create an OUTLINEhint_plan.create_outline()
View OUTLINEshint_plan.outlines_status
Enable an OUTLINEhint_plan.enable_outline()
Disable an OUTLINEhint_plan.disable_outline()
Delete an OUTLINEhint_plan.del_outline()

Supported versions

PostgreSQL versionMinimum minor engine version
PostgreSQL 162.0.16.9.9.0
PostgreSQL 142.0.14.13.28.0

To check your minor engine version, run SHOW polardb_version; or view it in the console. If the version is not supported, upgrade the minor engine version.

Prerequisites

Before you begin, ensure that you have:

  • A PolarDB for PostgreSQL cluster running a supported version (see Supported versions)

  • The pg_hint_plan extension installed at version 1.4.1 or later

  • An account with permissions to run DDL statements in the target database

Enable the OUTLINE feature

Step 1. Verify that pg_hint_plan is installed at version 1.4.1 or later:

SELECT extname, extversion >= '1.4.1' AS outline_version_ok
FROM pg_extension
WHERE extname = 'pg_hint_plan';

Expected output:

   extname    | outline_version_ok
--------------+--------------------
 pg_hint_plan | t
(1 row)

If the output differs, resolve the issue before proceeding:

IssueResolution
Extension not installedRun CREATE EXTENSION IF NOT EXISTS pg_hint_plan;
Version too oldRun ALTER EXTENSION pg_hint_plan UPDATE;
Run these statements in the target database using an account with the appropriate permissions.

Step 2. Set the pg_hint_plan.polar_enable_outline parameter to on. Go to in the console. This change does not restart the cluster.

Create an OUTLINE

Pass the SQL statement with the desired hint to hint_plan.create_outline(). The function extracts the hint and binds it to the SQL class.

CALL hint_plan.create_outline($$ SELECT /*+ Set(enable_bitmapscan off) */ * FROM t WHERE a = 1 $$);
If you get ERROR: invalid transaction termination when running this statement from Data Management Service (DMS), switch to another client such as psql. See Connect to a database cluster.

SQL matching rules

The SQL text you pass must match your application's query template. The following factors do not affect matching:

FactorExample
Whitespace, line breaks, and commentsAny extra spaces or -- comment
Parameter values (constants and variables)a = 1, a = $1, and a = 2 are treated identically
Keyword caseSELECT, select, and Select are equivalent
Number of parameters in a lista IN (1,2,3) and a IN (1,2) match the same SQL class. Exception: a IN (1) (single parameter) does NOT match a IN (1,2,3) (multiple parameters), because a single-element list is not normalized with a multi-element list.

The following factors do prevent a match:

  • Extra type casts (::), for example a::int

  • Schema-qualified table names, for example public.t instead of t

  • Different case for table or column names

View OUTLINEs

Query hint_plan.outlines_status to see all OUTLINEs in the current database:

SELECT * FROM hint_plan.outlines_status;
ColumnTypeDescription
idBIGINTAuto-generated primary key that uniquely identifies each OUTLINE
sql_idBIGINTThe SQL_ID that this OUTLINE is bound to
hintsTEXTThe hints bound to this OUTLINE
stateCHARACTER(1)Y = enabled, N = disabled
depends_relsTEXT[]All relations (tables and views) that the stabilized plan depends on
query_stringTEXTThe SQL statement used when creating this OUTLINE
create_userTEXTThe user who created this OUTLINE
create_timeTIMESTAMP WITHOUT TIME ZONEWhen the OUTLINE was created
total_hintsTEXTAggregated hints for the SQL_ID. If multiple OUTLINEs share the same SQL_ID, their hints are combined in ascending id order
callsBIGINTHow many times this OUTLINE has been applied

Enable or disable an OUTLINE

Use the OUTLINE id from hint_plan.outlines_status:

-- Enable OUTLINE with id = 1
CALL hint_plan.enable_outline(1);

-- Disable OUTLINE with id = 1
CALL hint_plan.disable_outline(1);

Delete an OUTLINE

CALL hint_plan.del_outline(1);

Usage notes

  • OUTLINE takes priority over inline hints. After you create an OUTLINE for a SQL class, any hints embedded in the original SQL are ignored. Only the OUTLINE hints apply.

  • Multiple OUTLINEs stack. You can create more than one OUTLINE for the same SQL class. The hints are combined in ascending id order.

  • OUTLINE and `hint_table` are mutually exclusive. Enabling OUTLINE disables the hint_table feature of pg_hint_plan automatically.

Performance considerations

OUTLINE uses an internal high-concurrency cache to minimize overhead. Under standard Sysbench stress testing with OUTLINE enabled and active, Transactions Per Second (TPS) and Queries Per Second (QPS) decrease by approximately 1% to 2%.

Complete example

This example shows how to stabilize an execution plan that switches between two indexes depending on optimizer cost estimates.

1. Enable OUTLINE. See Enable the OUTLINE feature.

2. Create a test table and populate it:

CREATE TABLE t(a int, b int, PRIMARY KEY(a));
CREATE INDEX ON t(b);
INSERT INTO t SELECT i, i FROM generate_series(1, 100000) i;
ANALYZE t;

3. Check the current plan. The optimizer chooses the index on column b:

EXPLAIN (costs off) SELECT * FROM t WHERE b = 1 AND a = 1;
QUERY PLAN
-------------------------------
 Index Scan using t_b_idx on t
   Index Cond: (b = 1)
   Filter: (a = 1)
(3 rows)

4. Use a hint to force the primary key index and confirm it works:

EXPLAIN (costs off) /*+IndexScan(t t_pkey) */ SELECT * FROM t WHERE b = 1 AND a = 1;
QUERY PLAN
------------------------------
 Index Scan using t_pkey on t
   Index Cond: (a = 1)
   Filter: (b = 1)
(3 rows)

5. Create an OUTLINE to lock in this plan:

CALL hint_plan.create_outline($$/*+IndexScan(t t_pkey) */ SELECT * FROM t WHERE b = 1 AND a = 1;$$);

6. Verify the OUTLINE is applied. Run the original query without any inline hint—the primary key index is still used:

EXPLAIN (costs off) SELECT * FROM t WHERE b = 1 AND a = 1;
QUERY PLAN
------------------------------
 Index Scan using t_pkey on t
   Index Cond: (a = 1)
   Filter: (b = 1)
(3 rows)

The OUTLINE also matches queries with different parameter values, added comments, or extra whitespace:

EXPLAIN (costs off) SELECT * -- comment
FROM t
WHERE b = 2 AND a = 4;
QUERY PLAN
------------------------------
 Index Scan using t_pkey on t
   Index Cond: (a = 4)
   Filter: (b = 2)
(3 rows)

7. Check the OUTLINE status:

SELECT * FROM hint_plan.outlines_status;
 id |        sql_id        |        hints        | state | depends_rels |                           query_string                           | create_user |        create_time         |     total_hints     | calls
----+----------------------+---------------------+-------+--------------+------------------------------------------------------------------+-------------+----------------------------+---------------------+-------
  1 | -3220256307655713529 | IndexScan(t t_pkey) | Y     | {public.t}   | /*+IndexScan(t t_pkey) */ SELECT * FROM t WHERE b = 1 AND a = 1; | postgres    | 2024-11-11 11:24:44.063143 | IndexScan(t t_pkey) |     2
(1 row)

8. When the OUTLINE is no longer needed, disable or delete it:

-- Disable
CALL hint_plan.disable_outline(1);

-- Or delete permanently
CALL hint_plan.del_outline(1);

After disabling or deleting the OUTLINE, the optimizer reverts to its original plan:

EXPLAIN (costs off) SELECT * FROM t WHERE b = 1 AND a = 1;
QUERY PLAN
-------------------------------
 Index Scan using t_b_idx on t
   Index Cond: (b = 1)
   Filter: (a = 1)
(3 rows)

Key concepts

TermDefinition
HINTAn optimizer hint embedded in an SQL comment that influences how the optimizer generates an execution plan
OUTLINEA binding that specifies which hint to apply to a class of SQL statements
OUTLINE DDLOperations that modify OUTLINEs: create, delete, enable, and disable
SQL_IDA unique identifier generated by the database to distinguish SQL classes. OUTLINE uses SQL_ID to match target statements