Skip to content

Stable13 #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
197145a
Prevent distributed deadlocks. Disable AQO for FDW queries.
danolivo Dec 3, 2020
626d5ee
Allow learning (and predicting for) on a ForeignScan, an Append, a Me…
danolivo Dec 4, 2020
386cd6d
Add support of postgres_fdw push-down.
danolivo Dec 4, 2020
0cd3ce3
Process GatherMergePath in get_path_clauses routine.
danolivo Dec 15, 2020
e8dcb5b
Add a foreign relation estimation hook into the core patch and AQO.
danolivo Jan 15, 2021
38d4f77
Add basic regression test on FDW support.
danolivo Jan 15, 2021
8291220
Add missed aqo_fdw.sql
danolivo Jan 19, 2021
9aff621
Prepare the insert_index routine for PGv14 signature
danolivo Jan 18, 2021
36c97ac
Change the license sentence in accordance with 2021.
danolivo Jan 19, 2021
34c640d
Fix the state:
danolivo Jan 19, 2021
fbf27d6
Rename aqo.details to aqo.show_details.
danolivo Jan 20, 2021
d8e18ce
Update the readme file in accordance with the new AQO version.
danolivo Jan 20, 2021
418c7d4
Bugfix of the aqo_fdw regress test
danolivo Jan 20, 2021
505c064
Update README.md
danolivo Feb 6, 2021
453bef5
Rename the aqo_details to aqo_show_details
danolivo Feb 18, 2021
d705b5d
Store selectivity cache data in the cache memory context instead of
danolivo Feb 18, 2021
2b20ff0
Change insert/update scheme for the ML-knowledge base.
danolivo Feb 18, 2021
436b3e6
Improve AQO makefile
danolivo Feb 18, 2021
8ec6572
Bugfix: don't create ignorance table in parallel worker.
danolivo Feb 18, 2021
d339ad0
Make the explain of AQO more readable.
danolivo Mar 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@

EXTENSION = aqo
EXTVERSION = 1.2
PGFILEDESC = "AQO - adaptive query optimization"
MODULES = aqo
PGFILEDESC = "AQO - Adaptive Query Optimization"
MODULE_big = aqo
OBJS = aqo.o auto_tuning.o cardinality_estimation.o cardinality_hooks.o \
hash.o machine_learning.o path_utils.o postprocessing.o preprocessing.o \
selectivity_cache.o storage.o utils.o $(WIN32RES)
selectivity_cache.o storage.o utils.o ignorance.o $(WIN32RES)

TAP_TESTS = 1

REGRESS = aqo_disabled \
aqo_controlled \
aqo_intelligent \
aqo_forced \
aqo_learn \
schema \
aqo_CVE-2020-14350
aqo_fdw \
aqo_CVE-2020-14350 \
gucs

fdw_srcdir = $(top_srcdir)/contrib/postgres_fdw
PG_CPPFLAGS += -I$(libpq_srcdir) -I$(fdw_srcdir)
EXTRA_REGRESS_OPTS=--temp-config=$(top_srcdir)/$(subdir)/conf.add
EXTRA_INSTALL = contrib/postgres_fdw

DATA = aqo--1.0.sql aqo--1.0--1.1.sql aqo--1.1--1.2.sql aqo--1.2.sql

MODULE_big = aqo
ifdef USE_PGXS
PG_CONFIG ?= pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
Expand Down
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ complicated queries.
## Installation

The module works with PostgreSQL 9.6 and above.
To avoid compatibility issues, the following branches in the git-repository are allocated:
* `stable9_6`.
* `stable11` - for PG v10 and v11.
* `stable12` - for PG v12.
* the `master` branch of the AQO repository correctly works with PGv13 and the PostgreSQL `master` branch.

The module contains a patch and an extension. Patch has to be applied to the
sources of PostgresSQL. Patch affects header files, that is why PostgreSQL
Expand All @@ -19,7 +24,7 @@ installed with `make install`.

```
cd postgresql-9.6 # enter postgresql source directory
git clone https://github.com/tigvarts/aqo.git contrib/aqo # clone aqo into contrib
git clone https://github.com/postgrespro/aqo.git contrib/aqo # clone aqo into contrib
patch -p1 --no-backup-if-mismatch < contrib/aqo/aqo_pg<version>.patch # patch postgresql
make clean && make && make install # recompile postgresql
cd contrib/aqo # enter aqo directory
Expand All @@ -28,7 +33,7 @@ make check # check whether it works
```

Tag `version` at the patch name corresponds to suitable PostgreSQL release.
For PostgreSQL 10 use aqo_pg10.patch; for PostgreSQL 11 use aqo_pg11.patch and so on.
For PostgreSQL 9.6 use the 'aqo_pg9_6.patch' file; PostgreSQL 10 use aqo_pg10.patch; for PostgreSQL 11 use aqo_pg11.patch and so on.
Also, you can see git tags at the master branch for more accurate definition of
suitable PostgreSQL version.

Expand All @@ -50,7 +55,7 @@ of per-database.

The typical case is follows: you have complicated query, which executes too
long. `EXPLAIN ANALYZE` shows, that the possible reason is bad cardinality
estimnation.
estimation.

Example:
```
Expand Down Expand Up @@ -127,16 +132,16 @@ When the plan stops changing, you can often observe performance improvement:
(23 rows)
```

The settings system in AQO works with normalized queries, i. e. queries with
removed constants. For example, the normalized version of
The settings system in AQO works with normalised queries, i. e. queries with
removed constants. For example, the normalised version of
`SELECT * FROM tbl WHERE a < 25 AND b = 'str';`
is
`SELECT * FROM tbl WHERE a < CONST and b = CONST;`

So the queries have equal normalization if and only if they differ only
So the queries have equal normalisation if and only if they differ only
in their constants.

Each normalized query has its own hash. The correspondence between normalized
Each normalised query has its own hash. The correspondence between normalised
query hash and query text is stored in aqo_query_texts table:
```
SELECT * FROM aqo_query_texts;
Expand Down Expand Up @@ -174,6 +179,10 @@ if the data tends to change significantly), you can do
`UPDATE SET aqo_learn=false WHERE query_hash = <query_hash>;`
before commit.

The extension includes two GUC's to display the executed cardinality predictions for a query.
The `aqo.show_details = 'on'` (default - off) allows to see the aqo cardinality prediction results for each node of a query plan and an AQO summary.
The `aqo.show_hash = 'on'` (default - off) will print hash signature for each plan node and overall query. It is system-specific information and should be used for situational analysis.

The more detailed reference of AQO settings mechanism is available further.

## Advanced tuning
Expand Down
131 changes: 128 additions & 3 deletions aqo.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,43 @@
* aqo.c
* Adaptive query optimization extension
*
* Copyright (c) 2016-2020, Postgres Professional
* Copyright (c) 2016-2021, Postgres Professional
*
* IDENTIFICATION
* aqo/aqo.c
*/

#include "aqo.h"
#include "ignorance.h"

#include "access/relation.h"
#include "access/table.h"
#include "catalog/pg_extension.h"
#include "commands/extension.h"

PG_MODULE_MAGIC;

void _PG_init(void);

#define AQO_MODULE_MAGIC (1234)

/* Strategy of determining feature space for new queries. */
int aqo_mode;
bool force_collect_stat;

/*
* Show special info in EXPLAIN mode.
*
* aqo_show_hash - show query class (hash) and a feature space value (hash)
* of each plan node. This is instance-dependent value and can't be used
* in regression and TAP tests.
*
* aqo_show_details - show AQO settings for this class and prediction
* for each plan node.
*/
bool aqo_show_hash;
bool aqo_show_details;

/* GUC variables */
static const struct config_enum_entry format_options[] = {
{"intelligent", AQO_MODE_INTELLIGENT, false},
Expand Down Expand Up @@ -76,12 +96,14 @@ post_parse_analyze_hook_type prev_post_parse_analyze_hook;
planner_hook_type prev_planner_hook;
ExecutorStart_hook_type prev_ExecutorStart_hook;
ExecutorEnd_hook_type prev_ExecutorEnd_hook;
set_baserel_rows_estimate_hook_type prev_set_foreign_rows_estimate_hook;
set_baserel_rows_estimate_hook_type prev_set_baserel_rows_estimate_hook;
get_parameterized_baserel_size_hook_type prev_get_parameterized_baserel_size_hook;
set_joinrel_size_estimates_hook_type prev_set_joinrel_size_estimates_hook;
get_parameterized_joinrel_size_hook_type prev_get_parameterized_joinrel_size_hook;
copy_generic_path_info_hook_type prev_copy_generic_path_info_hook;
ExplainOnePlan_hook_type prev_ExplainOnePlan_hook;
ExplainOneNode_hook_type prev_ExplainOneNode_hook;

/*****************************************************************************
*
Expand All @@ -102,7 +124,8 @@ _PG_init(void)
0,
NULL,
NULL,
NULL);
NULL
);

DefineCustomBoolVariable(
"aqo.force_collect_stat",
Expand All @@ -115,7 +138,46 @@ _PG_init(void)
NULL,
NULL,
NULL
);
);

DefineCustomBoolVariable(
"aqo.show_hash",
"Show query and node hash on explain.",
"Hash value depend on each instance and is not good to enable it in regression or TAP tests.",
&aqo_show_hash,
false,
PGC_USERSET,
0,
NULL,
NULL,
NULL
);

DefineCustomBoolVariable(
"aqo.show_details",
"Show AQO state on a query.",
NULL,
&aqo_show_details,
false,
PGC_USERSET,
0,
NULL,
NULL,
NULL
);

DefineCustomBoolVariable(
"aqo.log_ignorance",
"Log in a special table all feature spaces for which the AQO prediction was not successful.",
NULL,
&aqo_log_ignorance,
false,
PGC_SUSET,
0,
NULL,
set_ignorance,
NULL
);

prev_planner_hook = planner_hook;
planner_hook = aqo_planner;
Expand All @@ -126,6 +188,7 @@ _PG_init(void)
prev_ExecutorEnd_hook = ExecutorEnd_hook;
ExecutorEnd_hook = aqo_ExecutorEnd;
prev_set_baserel_rows_estimate_hook = set_baserel_rows_estimate_hook;
set_foreign_rows_estimate_hook = aqo_set_baserel_rows_estimate;
set_baserel_rows_estimate_hook = aqo_set_baserel_rows_estimate;
prev_get_parameterized_baserel_size_hook = get_parameterized_baserel_size_hook;
get_parameterized_baserel_size_hook = aqo_get_parameterized_baserel_size;
Expand All @@ -137,6 +200,8 @@ _PG_init(void)
copy_generic_path_info_hook = aqo_copy_generic_path_info;
prev_ExplainOnePlan_hook = ExplainOnePlan_hook;
ExplainOnePlan_hook = print_into_explain;
prev_ExplainOneNode_hook = ExplainOneNode_hook;
ExplainOneNode_hook = print_node_explain;
parampathinfo_postinit_hook = ppi_hook;

init_deactivated_queries_storage();
Expand All @@ -158,3 +223,63 @@ invalidate_deactivated_queries_cache(PG_FUNCTION_ARGS)
init_deactivated_queries_storage();
PG_RETURN_POINTER(NULL);
}

/*
* Return AQO schema's Oid or InvalidOid if that's not possible.
*/
Oid
get_aqo_schema(void)
{
Oid result;
Relation rel;
SysScanDesc scandesc;
HeapTuple tuple;
ScanKeyData entry[1];
Oid ext_oid;

/* It's impossible to fetch pg_aqo's schema now */
if (!IsTransactionState())
return InvalidOid;

ext_oid = get_extension_oid("aqo", true);
if (ext_oid == InvalidOid)
return InvalidOid; /* exit if pg_aqo does not exist */

ScanKeyInit(&entry[0],
#if PG_VERSION_NUM >= 120000
Anum_pg_extension_oid,
#else
ObjectIdAttributeNumber,
#endif
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(ext_oid));

rel = relation_open(ExtensionRelationId, AccessShareLock);
scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
NULL, 1, entry);
tuple = systable_getnext(scandesc);

/* We assume that there can be at most one matching tuple */
if (HeapTupleIsValid(tuple))
result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
else
result = InvalidOid;

systable_endscan(scandesc);
relation_close(rel, AccessShareLock);
return result;
}

/*
* Init userlock
*/
void
init_lock_tag(LOCKTAG *tag, uint32 key1, uint32 key2)
{
tag->locktag_field1 = AQO_MODULE_MAGIC;
tag->locktag_field2 = key1;
tag->locktag_field3 = key2;
tag->locktag_field4 = 0;
tag->locktag_type = LOCKTAG_USERLOCK;
tag->locktag_lockmethodid = USER_LOCKMETHOD;
}
Loading