Skip to content

Commit d1217d8

Browse files
committed
Code changes after the first step of review:
1. Improve AQO output readability. 2. Add code comments on non-portability of the AQO knowledge base. 3. Fix incorrect row values in the TAP tests for intelligent and learn modes. 4. Add comments on probabilistic nature of convergence by execution time. 5. Introduce the auto_tuning_convergence_error AQO parameter and set its value to 0.01 for reduce volatility of the TAP tests output. 6. Fix the bugs of the AQO update script from v1.1 to v1.2.
1 parent 8f8db28 commit d1217d8

File tree

10 files changed

+65
-81
lines changed

10 files changed

+65
-81
lines changed

aqo--1.1--1.2.sql

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ $$ LANGUAGE plpgsql;
1414
DO $$
1515
BEGIN
1616
EXECUTE format('ALTER TABLE public.aqo_data DROP CONSTRAINT %s',
17-
aqo_migrate_to_1_2_get_pk('aqo_data'::regclass),
17+
aqo_migrate_to_1_2_get_pk('public.aqo_data'::regclass),
1818
'aqo_queries_query_hash_idx');
1919
END
2020
$$;
@@ -27,7 +27,7 @@ DROP FUNCTION aqo_migrate_to_1_2_get_pk(regclass);
2727
--
2828

2929
-- Show query state at the AQO knowledge base
30-
CREATE FUNCTION public.aqo_status(hash int)
30+
CREATE OR REPLACE FUNCTION public.aqo_status(hash int)
3131
RETURNS TABLE (
3232
"learn" BOOL,
3333
"use aqo" BOOL,
@@ -48,57 +48,58 @@ SELECT learn_aqo,use_aqo,auto_tuning,fspace_hash,
4848
to_char(execution_time_with_aqo[n3],'9.99EEEE'),
4949
to_char(cardinality_error_with_aqo[n1],'9.99EEEE'),
5050
executions_with_aqo
51-
FROM aqo_queries aq, aqo_query_stat aqs,
51+
FROM public.aqo_queries aq, public.aqo_query_stat aqs,
5252
(SELECT array_length(n1,1) AS n1, array_length(n2,1) AS n2,
5353
array_length(n3,1) AS n3, array_length(n4,1) AS n4
5454
FROM
5555
(SELECT cardinality_error_with_aqo AS n1,
5656
cardinality_error_without_aqo AS n2,
5757
execution_time_with_aqo AS n3,
5858
execution_time_without_aqo AS n4
59-
FROM aqo_query_stat aqs WHERE
59+
FROM public.aqo_query_stat aqs WHERE
6060
aqs.query_hash = $1) AS al) AS q
6161
WHERE (aqs.query_hash = aq.query_hash) AND
6262
aqs.query_hash = $1;
6363
$func$ LANGUAGE SQL;
6464

65-
CREATE FUNCTION public.aqo_enable_query(hash int)
65+
CREATE OR REPLACE FUNCTION public.aqo_enable_query(hash int)
6666
RETURNS VOID
6767
AS $func$
68-
UPDATE aqo_queries SET
68+
UPDATE public.aqo_queries SET
6969
learn_aqo = 'true',
7070
use_aqo = 'true'
7171
WHERE query_hash = $1;
7272
$func$ LANGUAGE SQL;
7373

74-
CREATE FUNCTION public.aqo_disable_query(hash int)
74+
CREATE OR REPLACE FUNCTION public.aqo_disable_query(hash int)
7575
RETURNS VOID
7676
AS $func$
77-
UPDATE aqo_queries SET
77+
UPDATE public.aqo_queries SET
7878
learn_aqo = 'false',
7979
use_aqo = 'false',
8080
auto_tuning = 'false'
8181
WHERE query_hash = $1;
8282
$func$ LANGUAGE SQL;
8383

84-
CREATE FUNCTION public.aqo_clear_hist(hash int)
84+
CREATE OR REPLACE FUNCTION public.aqo_clear_hist(hash int)
8585
RETURNS VOID
8686
AS $func$
87-
DELETE FROM aqo_data WHERE fspace_hash=$1;
87+
DELETE FROM public.aqo_data WHERE fspace_hash=$1;
8888
$func$ LANGUAGE SQL;
8989

9090
-- Show queries that contains 'Never executed' nodes at the plan.
91-
CREATE FUNCTION public.aqo_ne_queries()
91+
CREATE OR REPLACE FUNCTION public.aqo_ne_queries()
9292
RETURNS SETOF int
9393
AS $func$
94-
SELECT query_hash FROM aqo_query_stat aqs WHERE -1 = ANY (cardinality_error_with_aqo::double precision[]);
94+
SELECT query_hash FROM public.aqo_query_stat aqs
95+
WHERE -1 = ANY (cardinality_error_with_aqo::double precision[]);
9596
$func$ LANGUAGE SQL;
9697

97-
CREATE FUNCTION public.aqo_drop(hash int)
98+
CREATE OR REPLACE FUNCTION public.aqo_drop(hash int)
9899
RETURNS VOID
99100
AS $func$
100-
DELETE FROM aqo_queries aq WHERE (aq.query_hash = $1);
101-
DELETE FROM aqo_data ad WHERE (ad.fspace_hash = $1);
102-
DELETE FROM aqo_query_stat aq WHERE (aq.query_hash = $1);
103-
DELETE FROM aqo_query_texts aq WHERE (aq.query_hash = $1);
101+
DELETE FROM public.aqo_queries aq WHERE (aq.query_hash = $1);
102+
DELETE FROM public.aqo_data ad WHERE (ad.fspace_hash = $1);
103+
DELETE FROM public.aqo_query_stat aq WHERE (aq.query_hash = $1);
104+
DELETE FROM public.aqo_query_texts aq WHERE (aq.query_hash = $1);
104105
$func$ LANGUAGE SQL;

aqo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ extern int auto_tuning_window_size;
226226
extern double auto_tuning_exploration;
227227
extern int auto_tuning_max_iterations;
228228
extern int auto_tuning_infinite_loop;
229+
extern double auto_tuning_convergence_error;
229230

230231
/* Machine learning parameters */
231232

aqo_pg12.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ index 92969636b7..d05b07e037 100644
5959
+ error = 100. * (plan->predicted_cardinality - (rows*wrkrs))
6060
+ / plan->predicted_cardinality;
6161
+ appendStringInfo(es->str,
62-
+ " (AQO predicted: cardinality=%lf, error=%.0lf%%, fsspace_hash=%d)",
62+
+ " (AQO: cardinality=%.0lf, error=%.0lf%%, fsspace_hash=%d)",
6363
+ plan->predicted_cardinality, error, plan->fss_hash);
6464
+ }
6565
+ else

auto_tuning.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
*
1010
*****************************************************************************/
1111

12+
/*
13+
* Auto tuning criteria criteria of an query convergence by overall cardinality
14+
* of plan nodes.
15+
*/
16+
double auto_tuning_convergence_error = 0.01;
17+
1218
static double get_mean(double *elems, int nelems);
1319
static double get_estimation(double *elems, int nelems);
1420
static bool is_stable(double *elems, int nelems);
@@ -52,7 +58,7 @@ get_estimation(double *elems, int nelems)
5258
}
5359

5460
/*
55-
* Checks whether the series is stable with absolute or relative error 0.1.
61+
* Checks whether the series is stable with absolute or relative error.
5662
*/
5763
bool
5864
is_stable(double *elems, int nelems)
@@ -65,15 +71,15 @@ is_stable(double *elems, int nelems)
6571
est = get_mean(elems, nelems - 1);
6672
last = elems[nelems - 1];
6773

68-
return (est * 1.1 > last || est + 0.1 > last) &&
69-
(est * 0.9 < last || est - 0.1 < last);
74+
return (est * (1. + auto_tuning_convergence_error) > last || est + auto_tuning_convergence_error > last) &&
75+
(est * (1. - auto_tuning_max_error) < last || est - auto_tuning_max_error < last);
7076
}
7177

7278
/*
7379
* Tests whether cardinality qualities series is converged, i. e. learning
7480
* process may be considered as finished.
7581
* Now it checks whether the cardinality quality stopped decreasing with
76-
* absolute or relative error 0.1.
82+
* absolute or relative error.
7783
*/
7884
bool
7985
converged_cq(double *elems, int nelems)
@@ -147,6 +153,11 @@ automatical_query_tuning(int query_hash, QueryStat * stat)
147153
query_context.use_aqo = true;
148154
else
149155
{
156+
/*
157+
* Query is converged by cardinality error. Now AQO checks convergence
158+
* by execution time. It is volatile, probabilistic part of code.
159+
* XXX: this logic of auto tuning may be reworked later.
160+
*/
150161
t_aqo = get_estimation(stat->execution_time_with_aqo,
151162
stat->execution_time_with_aqo_size) +
152163
get_estimation(stat->planning_time_with_aqo,

expected/aqo_intelligent.out

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,9 @@ FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3
476476
WHERE t1.a = t2.b AND t2.a = t3.b;
477477
QUERY PLAN
478478
-------------------------------------------------------------------------------
479-
Hash Join (cost=2.90..4.65 rows=20 width=12)
479+
Hash Join (cost=2.90..4.64 rows=18 width=12)
480480
Hash Cond: (t2.a = t3.b)
481-
-> Hash Join (cost=1.45..2.92 rows=20 width=8)
481+
-> Hash Join (cost=1.45..2.92 rows=19 width=8)
482482
Hash Cond: (t1.a = t2.b)
483483
-> Seq Scan on aqo_test1 t1 (cost=0.00..1.20 rows=20 width=4)
484484
-> Hash (cost=1.20..1.20 rows=20 width=8)
@@ -492,11 +492,11 @@ FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3, aqo_test1 AS t4
492492
WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
493493
QUERY PLAN
494494
-------------------------------------------------------------------------------------
495-
Hash Join (cost=4.35..6.37 rows=20 width=16)
495+
Hash Join (cost=4.35..6.33 rows=17 width=16)
496496
Hash Cond: (t3.a = t4.b)
497-
-> Hash Join (cost=2.90..4.65 rows=20 width=12)
497+
-> Hash Join (cost=2.90..4.64 rows=18 width=12)
498498
Hash Cond: (t2.a = t3.b)
499-
-> Hash Join (cost=1.45..2.92 rows=20 width=8)
499+
-> Hash Join (cost=1.45..2.92 rows=19 width=8)
500500
Hash Cond: (t1.a = t2.b)
501501
-> Seq Scan on aqo_test1 t1 (cost=0.00..1.20 rows=20 width=4)
502502
-> Hash (cost=1.20..1.20 rows=20 width=8)
@@ -507,37 +507,6 @@ WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
507507
-> Seq Scan on aqo_test1 t4 (cost=0.00..1.20 rows=20 width=8)
508508
(13 rows)
509509

510-
EXPLAIN verbose SELECT t1.a AS a, t2.a AS b, t3.a AS c, t4.a AS d
511-
FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3, aqo_test1 AS t4
512-
WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
513-
QUERY PLAN
514-
--------------------------------------------------------------------------------------------
515-
Hash Join (cost=4.35..6.37 rows=20 width=16)
516-
Output: t1.a, t2.a, t3.a, t4.a
517-
Hash Cond: (t3.a = t4.b)
518-
-> Hash Join (cost=2.90..4.65 rows=20 width=12)
519-
Output: t1.a, t2.a, t3.a
520-
Hash Cond: (t2.a = t3.b)
521-
-> Hash Join (cost=1.45..2.92 rows=20 width=8)
522-
Output: t1.a, t2.a
523-
Hash Cond: (t1.a = t2.b)
524-
-> Seq Scan on public.aqo_test1 t1 (cost=0.00..1.20 rows=20 width=4)
525-
Output: t1.a, t1.b
526-
-> Hash (cost=1.20..1.20 rows=20 width=8)
527-
Output: t2.a, t2.b
528-
-> Seq Scan on public.aqo_test1 t2 (cost=0.00..1.20 rows=20 width=8)
529-
Output: t2.a, t2.b
530-
-> Hash (cost=1.20..1.20 rows=20 width=8)
531-
Output: t3.a, t3.b
532-
-> Seq Scan on public.aqo_test1 t3 (cost=0.00..1.20 rows=20 width=8)
533-
Output: t3.a, t3.b
534-
-> Hash (cost=1.20..1.20 rows=20 width=8)
535-
Output: t4.a, t4.b
536-
-> Seq Scan on public.aqo_test1 t4 (cost=0.00..1.20 rows=20 width=8)
537-
Output: t4.a, t4.b
538-
Using aqo: true
539-
(24 rows)
540-
541510
DROP INDEX aqo_test0_idx_a;
542511
DROP TABLE aqo_test0;
543512
DROP INDEX aqo_test1_idx_a;

expected/aqo_learn.out

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,9 @@ FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3
395395
WHERE t1.a = t2.b AND t2.a = t3.b;
396396
QUERY PLAN
397397
-------------------------------------------------------------------------------
398-
Hash Join (cost=2.90..4.65 rows=20 width=12)
398+
Hash Join (cost=2.90..4.64 rows=18 width=12)
399399
Hash Cond: (t2.a = t3.b)
400-
-> Hash Join (cost=1.45..2.92 rows=20 width=8)
400+
-> Hash Join (cost=1.45..2.92 rows=19 width=8)
401401
Hash Cond: (t1.a = t2.b)
402402
-> Seq Scan on aqo_test1 t1 (cost=0.00..1.20 rows=20 width=4)
403403
-> Hash (cost=1.20..1.20 rows=20 width=8)
@@ -411,11 +411,11 @@ FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3, aqo_test1 AS t4
411411
WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
412412
QUERY PLAN
413413
-------------------------------------------------------------------------------------
414-
Hash Join (cost=4.35..6.37 rows=20 width=16)
414+
Hash Join (cost=4.35..6.33 rows=17 width=16)
415415
Hash Cond: (t3.a = t4.b)
416-
-> Hash Join (cost=2.90..4.65 rows=20 width=12)
416+
-> Hash Join (cost=2.90..4.64 rows=18 width=12)
417417
Hash Cond: (t2.a = t3.b)
418-
-> Hash Join (cost=1.45..2.92 rows=20 width=8)
418+
-> Hash Join (cost=1.45..2.92 rows=19 width=8)
419419
Hash Cond: (t1.a = t2.b)
420420
-> Seq Scan on aqo_test1 t1 (cost=0.00..1.20 rows=20 width=4)
421421
-> Hash (cost=1.20..1.20 rows=20 width=8)

hash.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static bool clause_is_eq_clause(Expr *clause);
4545
/*
4646
* Computes hash for given query.
4747
* Hash is supposed to be constant-insensitive.
48+
* XXX: Hashing depend on Oids of database objects. It is restrict usability of
49+
* the AQO knowledge base by current database at current Postgres instance.
4850
*/
4951
int
5052
get_query_hash(Query *parse, const char *query_text)
@@ -149,7 +151,11 @@ get_fss_for_object(List *clauselist, List *selectivities, List *relidslist,
149151
*nfeatures = n - sh;
150152
(*features) = repalloc(*features, (*nfeatures) * sizeof(**features));
151153

152-
/* Generate feature subspace hash */
154+
/*
155+
* Generate feature subspace hash.
156+
* XXX: Remember! that relidslist_hash isn't portable between postgres
157+
* instances.
158+
*/
153159
clauses_hash = get_int_array_hash(sorted_clauses, *nfeatures);
154160
eclasses_hash = get_int_array_hash(eclass_hash, nargs);
155161
relidslist_hash = get_relidslist_hash(relidslist);

machine_learning.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,12 @@ double
9696
OkNNr_predict(int nrows, int ncols, double **matrix, const double *targets,
9797
double *features)
9898
{
99-
double distances[aqo_K];
100-
int i;
101-
int idx[aqo_K]; /* indexes of nearest neighbors */
102-
double w[aqo_K];
103-
double w_sum;
104-
double result = 0;
99+
double distances[aqo_K];
100+
int i;
101+
int idx[aqo_K]; /* indexes of nearest neighbors */
102+
double w[aqo_K];
103+
double w_sum;
104+
double result = 0;
105105

106106
for (i = 0; i < nrows; ++i)
107107
distances[i] = fs_distance(matrix[i], features, ncols);

sql/aqo_intelligent.sql

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,6 @@ EXPLAIN SELECT t1.a AS a, t2.a AS b, t3.a AS c, t4.a AS d
207207
FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3, aqo_test1 AS t4
208208
WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
209209

210-
EXPLAIN verbose SELECT t1.a AS a, t2.a AS b, t3.a AS c, t4.a AS d
211-
FROM aqo_test1 AS t1, aqo_test1 AS t2, aqo_test1 AS t3, aqo_test1 AS t4
212-
WHERE t1.a = t2.b AND t2.a = t3.b AND t3.a = t4.b;
213-
214210
DROP INDEX aqo_test0_idx_a;
215211
DROP TABLE aqo_test0;
216212

utils.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,18 @@ palloc_query_stat(void)
9999
MemoryContext oldCxt;
100100

101101
oldCxt = MemoryContextSwitchTo(AQOMemoryContext);
102-
res = palloc0(sizeof(*res));
103-
res->execution_time_with_aqo = palloc(aqo_stat_size *
102+
res = palloc0(sizeof(QueryStat));
103+
res->execution_time_with_aqo = palloc0(aqo_stat_size *
104104
sizeof(res->execution_time_with_aqo[0]));
105-
res->execution_time_without_aqo = palloc(aqo_stat_size *
105+
res->execution_time_without_aqo = palloc0(aqo_stat_size *
106106
sizeof(res->execution_time_without_aqo[0]));
107-
res->planning_time_with_aqo = palloc(aqo_stat_size *
107+
res->planning_time_with_aqo = palloc0(aqo_stat_size *
108108
sizeof(res->planning_time_with_aqo[0]));
109-
res->planning_time_without_aqo = palloc(aqo_stat_size *
109+
res->planning_time_without_aqo = palloc0(aqo_stat_size *
110110
sizeof(res->planning_time_without_aqo[0]));
111-
res->cardinality_error_with_aqo = palloc(aqo_stat_size *
111+
res->cardinality_error_with_aqo = palloc0(aqo_stat_size *
112112
sizeof(res->cardinality_error_with_aqo[0]));
113-
res->cardinality_error_without_aqo = palloc(aqo_stat_size *
113+
res->cardinality_error_without_aqo = palloc0(aqo_stat_size *
114114
sizeof(res->cardinality_error_without_aqo[0]));
115115
MemoryContextSwitchTo(oldCxt);
116116

0 commit comments

Comments
 (0)