Skip to content

Commit de286fe

Browse files
committed
Fix some problems found during underwent of the AQO by Join-Order-Benchmark:
1. Minor code improvements 2. Introduce the show_cardinality_errors(bool) routine that can show cardinality errors detected by the AQO that made during last execution under or without AQO control. 3. Ignore queries that don't touch any database relations.
1 parent afd6e98 commit de286fe

File tree

8 files changed

+174
-101
lines changed

8 files changed

+174
-101
lines changed

aqo--1.3--1.4.sql

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,60 @@
55

66
ALTER TABLE public.aqo_data ADD COLUMN reliability double precision [];
77

8+
DROP FUNCTION public.top_error_queries(int);
9+
10+
--
11+
-- Get cardinality error of queries the last time they were executed.
12+
-- IN:
13+
-- controlled - show queries executed under a control of AQO (true);
14+
-- executed without an AQO control, but AQO has a stat on the query (false).
815
--
9-
-- Get IDs of queries having the largest cardinality error when last executed.
16+
-- OUT:
1017
-- num - sequental number. Smaller number corresponds to higher error.
11-
-- qhash - ID of a query.
12-
-- error - AQO error calculated over plan nodes of the query.
18+
-- id - ID of a query.
19+
-- fshash - feature space. Usually equal to zero or ID.
20+
-- error - AQO error that calculated on plan nodes of the query.
21+
-- nexecs - number of executions of queries associated with this ID.
1322
--
14-
CREATE OR REPLACE FUNCTION public.show_cardinality_errors()
15-
RETURNS TABLE(num bigint, id bigint, error float)
23+
CREATE OR REPLACE FUNCTION public.show_cardinality_errors(controlled boolean)
24+
RETURNS TABLE(num bigint, id bigint, fshash bigint, error float, nexecs bigint)
1625
AS $$
1726
BEGIN
27+
IF (controlled) THEN
28+
RETURN QUERY
29+
SELECT
30+
row_number() OVER (ORDER BY (cerror, query_id, fs_hash) DESC) AS nn,
31+
query_id, fs_hash, cerror, execs
32+
FROM (
33+
SELECT
34+
aq.query_hash AS query_id,
35+
aq.fspace_hash AS fs_hash,
36+
cardinality_error_with_aqo[array_length(cardinality_error_with_aqo, 1)] AS cerror,
37+
executions_with_aqo AS execs
38+
FROM public.aqo_queries aq JOIN public.aqo_query_stat aqs
39+
ON aq.query_hash = aqs.query_hash
40+
WHERE TRUE = ANY (SELECT unnest(cardinality_error_with_aqo) IS NOT NULL)
41+
) AS q1
42+
ORDER BY nn ASC;
43+
ELSE
1844
RETURN QUERY
19-
SELECT
20-
row_number() OVER (ORDER BY (cerror, qhash) DESC) AS nn,
21-
qhash, cerror
22-
FROM (
23-
SELECT
24-
aq.query_hash AS qhash,
25-
cardinality_error_with_aqo[array_length(cardinality_error_with_aqo, 1)] AS cerror
26-
FROM public.aqo_queries aq JOIN public.aqo_query_stat aqs
27-
ON aq.query_hash = aqs.query_hash
28-
WHERE TRUE = ANY (SELECT unnest(cardinality_error_with_aqo) IS NOT NULL)
29-
) AS q1
30-
ORDER BY nn ASC;
45+
SELECT
46+
row_number() OVER (ORDER BY (cerror, query_id, fs_hash) DESC) AS nn,
47+
query_id, fs_hash, cerror, execs
48+
FROM (
49+
SELECT
50+
aq.query_hash AS query_id,
51+
aq.fspace_hash AS fs_hash,
52+
array_avg(cardinality_error_without_aqo) AS cerror,
53+
executions_without_aqo AS execs
54+
FROM public.aqo_queries aq JOIN public.aqo_query_stat aqs
55+
ON aq.query_hash = aqs.query_hash
56+
WHERE TRUE = ANY (SELECT unnest(cardinality_error_without_aqo) IS NOT NULL)
57+
) AS q1
58+
ORDER BY (nn) ASC;
59+
END IF;
3160
END;
3261
$$ LANGUAGE plpgsql;
3362

34-
COMMENT ON FUNCTION public.show_cardinality_errors() IS
35-
'Get cardinality error of last query execution. Return queries having the largest error.';
63+
COMMENT ON FUNCTION public.show_cardinality_errors(boolean) IS
64+
'Get cardinality error of queries the last time they were executed. Order queries according to an error value.';

expected/gucs.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ EXPLAIN (ANALYZE, VERBOSE, COSTS OFF, TIMING OFF, SUMMARY OFF)
3030

3131
-- Check existence of the interface functions.
3232
SELECT obj_description('public.show_cardinality_errors'::regproc::oid);
33-
obj_description
34-
-----------------------------------------------------------------------------------------
35-
Get cardinality error of last query execution. Return queries having the largest error.
33+
obj_description
34+
---------------------------------------------------------------------------------------------------------------
35+
Get cardinality error of queries the last time they were executed. Order queries according to an error value.
3636
(1 row)
3737

3838
DROP EXTENSION aqo;

expected/top_queries.out

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,31 @@ CREATE EXTENSION aqo;
22
SET aqo.mode = 'disabled';
33
SET aqo.force_collect_stat = 'on';
44
--
5-
-- num of generate_series(1,1000000) query should be the first
5+
-- Dummy test. CREATE TABLE shouldn't find in the ML storage. But a simple
6+
-- select must be in. Also here we test on gathering a stat on temp and plain
7+
-- relations.
68
--
7-
SELECT count(*) FROM generate_series(1,1000000);
8-
count
9-
---------
10-
1000000
9+
CREATE TEMP TABLE ttt AS SELECT count(*) AS cnt FROM generate_series(1,10);
10+
CREATE TABLE ttp AS SELECT count(*) AS cnt FROM generate_series(1,10);
11+
SELECT count(*) AS cnt FROM ttt WHERE cnt % 100 = 0;
12+
cnt
13+
-----
14+
0
15+
(1 row)
16+
17+
SELECT count(*) AS cnt FROM ttp WHERE cnt % 100 = 0;
18+
cnt
19+
-----
20+
0
1121
(1 row)
1222

13-
SELECT num FROM top_time_queries(10) AS tt WHERE
14-
tt.fspace_hash = (SELECT fspace_hash FROM aqo_queries WHERE
15-
aqo_queries.query_hash = (SELECT aqo_query_texts.query_hash FROM aqo_query_texts
16-
WHERE query_text = 'SELECT count(*) FROM generate_series(1,1000000);'));
17-
NOTICE: Top 10 execution time queries
23+
SELECT num FROM top_time_queries(3);
24+
NOTICE: Top 3 execution time queries
1825
num
1926
-----
2027
1
21-
(1 row)
28+
2
29+
(2 rows)
2230

2331
--
2432
-- num of query uses table t2 should be bigger than num of query uses table t1 and be the first
@@ -39,13 +47,23 @@ SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y
3947
31
4048
(1 row)
4149

42-
SELECT num FROM top_error_queries(10) AS te WHERE
43-
te.fspace_hash = (SELECT fspace_hash FROM aqo_queries WHERE
44-
aqo_queries.query_hash = (SELECT aqo_query_texts.query_hash FROM aqo_query_texts
45-
WHERE query_text = 'SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;'));
46-
NOTICE: Top 10 cardinality error queries
47-
num
48-
-----
49-
1
50+
SELECT num, to_char(error, '9.99EEEE') FROM show_cardinality_errors(false) AS te
51+
WHERE te.fshash = (
52+
SELECT fspace_hash FROM aqo_queries
53+
WHERE aqo_queries.query_hash = (
54+
SELECT aqo_query_texts.query_hash FROM aqo_query_texts
55+
WHERE query_text = 'SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;'
56+
)
57+
);
58+
num | to_char
59+
-----+-----------
60+
1 | 1.94e+00
61+
(1 row)
62+
63+
-- Should return zero
64+
SELECT count(*) FROM show_cardinality_errors(true);
65+
count
66+
-------
67+
0
5068
(1 row)
5169

expected/unsupported.out

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -541,19 +541,43 @@ EXPLAIN (COSTS OFF)
541541
-- XXX: Do we stuck into an unstable behavior of an error value?
542542
-- Live with this variant of the test for some time.
543543
SELECT
544-
num,
545-
to_char(error, '9.99EEEE')::text AS error
546-
FROM public.show_cardinality_errors()
547-
WHERE error > 0.;
548-
num | error
549-
-----+-----------
550-
1 | 9.69e+02
551-
2 | 1.15e+02
552-
3 | 3.00e+01
553-
4 | 3.00e+01
554-
5 | 3.00e+01
555-
6 | 1.33e+00
556-
(6 rows)
544+
num, to_char(error, '9.99EEEE')::text AS error, query_text
545+
FROM public.show_cardinality_errors(true) cef, aqo_query_texts aqt
546+
WHERE aqt.query_hash = cef.id
547+
ORDER BY (error, md5(query_text)) DESC;
548+
num | error | query_text
549+
-----+-----------+------------------------------------------------------------------------------------------------
550+
1 | 1.15e+02 | SELECT count(*) FROM t WHERE x < 3 AND mod(x,3) = 1;
551+
3 | 3.00e+01 | SELECT count(*) FROM (SELECT count(*) FROM t1 GROUP BY (x,y)) AS q1;
552+
4 | 3.00e+01 | SELECT count(*) FROM (SELECT x, y FROM t1 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;
553+
2 | 3.00e+01 | SELECT count(*) FROM (SELECT count(*) FROM t1 GROUP BY (x,x*y)) AS q1;
554+
5 | 1.33e+00 | SELECT count(*) FROM (SELECT * FROM t GROUP BY (x) HAVING x > 3) AS q1;
555+
11 | 0.00e+00 | SELECT * FROM +
556+
| | (SELECT * FROM t WHERE x < 0) AS t0 +
557+
| | JOIN +
558+
| | (SELECT * FROM t WHERE x > 20) AS t1 +
559+
| | USING(x);
560+
10 | 0.00e+00 | SELECT count(*) FROM t WHERE x = (SELECT avg(x) FROM t t0 WHERE t0.x = t.x);
561+
12 | 0.00e+00 | EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +
562+
| | SELECT count(*) FROM t WHERE +
563+
| | x = (SELECT avg(x) FROM t t0 WHERE t0.x = t.x + 21) OR +
564+
| | x IN (SELECT avg(x) FROM t t0 WHERE t0.x = t.x + 21);
565+
8 | 0.00e+00 | SELECT count(*) FROM ( +
566+
| | SELECT count(*) AS x FROM ( +
567+
| | SELECT count(*) FROM t1 GROUP BY (x,y) +
568+
| | ) AS q1 +
569+
| | ) AS q2 +
570+
| | WHERE q2.x > 1;
571+
9 | 0.00e+00 | SELECT count(*) FROM t WHERE x = (SELECT avg(x) FROM t WHERE x = 1);
572+
6 | 0.00e+00 | EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +
573+
| | SELECT count(*) FROM t WHERE (SELECT avg(x) FROM t t0 WHERE t0.x = t.x) = +
574+
| | (SELECT avg(x) FROM t t0 WHERE t0.x = t.x);
575+
7 | 0.00e+00 | SELECT count(*) FROM +
576+
| | (SELECT * FROM t WHERE x % 3 < (SELECT avg(x) FROM t t0 WHERE t0.x = t.x)) AS q1 +
577+
| | JOIN +
578+
| | (SELECT * FROM t WHERE x % 3 < (SELECT avg(x) FROM t t0 WHERE t0.x <> t.x)) AS q2 +
579+
| | ON q1.x = q2.x+1;
580+
(12 rows)
557581

558582
DROP TABLE t,t1 CASCADE;
559583
SELECT public.clean_aqo_data();
@@ -563,30 +587,13 @@ NOTICE: Cleaning aqo_data records
563587

564588
(1 row)
565589

566-
-- TODO: figure out with remaining queries in the ML storage.
590+
-- Look for any remaining queries in the ML storage.
567591
SELECT num, to_char(error, '9.99EEEE')::text AS error, query_text
568-
FROM public.show_cardinality_errors() cef, aqo_query_texts aqt
592+
FROM public.show_cardinality_errors(true) cef, aqo_query_texts aqt
569593
WHERE aqt.query_hash = cef.id
570594
ORDER BY (error, md5(query_text)) DESC;
571-
num | error | query_text
572-
-----+-----------+-------------------------------------------------------------------------------------------
573-
1 | 9.69e+02 | SELECT str FROM expln(' +
574-
| | EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +
575-
| | SELECT count(*) FROM +
576-
| | (SELECT * FROM t WHERE x % 3 < (SELECT avg(x) FROM t t0 WHERE t0.x = t.x)) AS q1 +
577-
| | JOIN +
578-
| | (SELECT * FROM t WHERE x % 3 < (SELECT avg(x) FROM t t0 WHERE t0.x <> t.x)) AS q2+
579-
| | ON q1.x = q2.x+1; +
580-
| | ') AS str WHERE str NOT LIKE '%Memory Usage%';
581-
2 | 3.27e+02 | SELECT +
582-
| | num, +
583-
| | to_char(error, '9.99EEEE')::text AS error +
584-
| | FROM public.show_cardinality_errors() +
585-
| | WHERE error > 0.;
586-
5 | 0.00e+00 | CREATE TABLE t AS SELECT (gs.* / 50) AS x FROM generate_series(1,1000) AS gs;
587-
4 | 0.00e+00 | SELECT public.clean_aqo_data();
588-
3 | 0.00e+00 | CREATE TABLE t1 AS SELECT mod(gs,10) AS x, mod(gs+1,10) AS y +
589-
| | FROM generate_series(1,1000) AS gs;
590-
(5 rows)
595+
num | error | query_text
596+
-----+-------+------------
597+
(0 rows)
591598

592599
DROP EXTENSION aqo;

preprocessing.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,19 @@ disable_aqo_for_query(void)
368368

369369
/*
370370
* Examine a fully-parsed query, and return TRUE iff any relation underlying
371-
* the query is a system relation.
371+
* the query is a system relation or no one relation touched by the query.
372372
*/
373373
static bool
374374
isQueryUsingSystemRelation(Query *query)
375375
{
376-
return isQueryUsingSystemRelation_walker((Node *) query, NULL);
376+
bool trivQuery = true;
377+
bool result;
378+
379+
result = isQueryUsingSystemRelation_walker((Node *) query, &trivQuery);
380+
381+
if (result || trivQuery)
382+
return true;
383+
return false;
377384
}
378385

379386

@@ -412,10 +419,13 @@ isQueryUsingSystemRelation_walker(Node *node, void *context)
412419
Relation rel = table_open(rte->relid, AccessShareLock);
413420
bool is_catalog = IsCatalogRelation(rel);
414421
bool is_aqo_rel = IsAQORelation(rel);
422+
bool *trivQuery = (bool *) context;
415423

416424
table_close(rel, AccessShareLock);
417425
if (is_catalog || is_aqo_rel)
418426
return true;
427+
428+
*trivQuery = false;
419429
}
420430
else if (rte->rtekind == RTE_FUNCTION)
421431
{

sql/top_queries.sql

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ SET aqo.mode = 'disabled';
33
SET aqo.force_collect_stat = 'on';
44

55
--
6-
-- num of generate_series(1,1000000) query should be the first
6+
-- Dummy test. CREATE TABLE shouldn't find in the ML storage. But a simple
7+
-- select must be in. Also here we test on gathering a stat on temp and plain
8+
-- relations.
79
--
8-
SELECT count(*) FROM generate_series(1,1000000);
9-
SELECT num FROM top_time_queries(10) AS tt WHERE
10-
tt.fspace_hash = (SELECT fspace_hash FROM aqo_queries WHERE
11-
aqo_queries.query_hash = (SELECT aqo_query_texts.query_hash FROM aqo_query_texts
12-
WHERE query_text = 'SELECT count(*) FROM generate_series(1,1000000);'));
10+
CREATE TEMP TABLE ttt AS SELECT count(*) AS cnt FROM generate_series(1,10);
11+
CREATE TABLE ttp AS SELECT count(*) AS cnt FROM generate_series(1,10);
12+
SELECT count(*) AS cnt FROM ttt WHERE cnt % 100 = 0;
13+
SELECT count(*) AS cnt FROM ttp WHERE cnt % 100 = 0;
14+
SELECT num FROM top_time_queries(3);
1315

1416
--
1517
-- num of query uses table t2 should be bigger than num of query uses table t1 and be the first
@@ -21,7 +23,14 @@ CREATE TABLE t2 AS SELECT mod(gs,10) AS x, mod(gs+1,10) AS y
2123
SELECT count(*) FROM (SELECT x, y FROM t1 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;
2224
SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;
2325

24-
SELECT num FROM top_error_queries(10) AS te WHERE
25-
te.fspace_hash = (SELECT fspace_hash FROM aqo_queries WHERE
26-
aqo_queries.query_hash = (SELECT aqo_query_texts.query_hash FROM aqo_query_texts
27-
WHERE query_text = 'SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;'));
26+
SELECT num, to_char(error, '9.99EEEE') FROM show_cardinality_errors(false) AS te
27+
WHERE te.fshash = (
28+
SELECT fspace_hash FROM aqo_queries
29+
WHERE aqo_queries.query_hash = (
30+
SELECT aqo_query_texts.query_hash FROM aqo_query_texts
31+
WHERE query_text = 'SELECT count(*) FROM (SELECT x, y FROM t2 GROUP BY GROUPING SETS ((x,y), (x), (y), ())) AS q1;'
32+
)
33+
);
34+
35+
-- Should return zero
36+
SELECT count(*) FROM show_cardinality_errors(true);

sql/unsupported.sql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,18 @@ EXPLAIN (COSTS OFF)
157157
-- XXX: Do we stuck into an unstable behavior of an error value?
158158
-- Live with this variant of the test for some time.
159159
SELECT
160-
num,
161-
to_char(error, '9.99EEEE')::text AS error
162-
FROM public.show_cardinality_errors()
163-
WHERE error > 0.;
160+
num, to_char(error, '9.99EEEE')::text AS error, query_text
161+
FROM public.show_cardinality_errors(true) cef, aqo_query_texts aqt
162+
WHERE aqt.query_hash = cef.id
163+
ORDER BY (error, md5(query_text)) DESC;
164164

165165
DROP TABLE t,t1 CASCADE;
166166

167167
SELECT public.clean_aqo_data();
168168

169-
-- TODO: figure out with remaining queries in the ML storage.
169+
-- Look for any remaining queries in the ML storage.
170170
SELECT num, to_char(error, '9.99EEEE')::text AS error, query_text
171-
FROM public.show_cardinality_errors() cef, aqo_query_texts aqt
171+
FROM public.show_cardinality_errors(true) cef, aqo_query_texts aqt
172172
WHERE aqt.query_hash = cef.id
173173
ORDER BY (error, md5(query_text)) DESC;
174174

t/001_pgbench.pl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,24 @@
133133
'analytical queries in pgbench (disabled mode)');
134134

135135
$res = $node->safe_psql('postgres',
136-
"SELECT count(*) FROM top_error_queries(10) v
137-
JOIN aqo_query_texts t ON (t.query_hash = v.fspace_hash)
136+
"SELECT count(*) FROM show_cardinality_errors(false) v
137+
JOIN aqo_query_texts t ON (t.query_hash = v.id)
138138
WHERE v.error > 0. AND t.query_text LIKE '%pgbench_accounts%'");
139139
is($res, 3);
140140
$res = $node->safe_psql('postgres',
141-
"SELECT * FROM top_error_queries(10) v
142-
JOIN aqo_query_texts t ON (t.query_hash = v.fspace_hash)
141+
"SELECT * FROM show_cardinality_errors(false) v
142+
JOIN aqo_query_texts t ON (t.query_hash = v.id)
143143
WHERE v.error > 0. AND t.query_text LIKE '%pgbench_accounts%'");
144144
note("\n TopN: \n $res \n");
145145
$res = $node->safe_psql('postgres',
146-
"SELECT v.error, t.query_text FROM top_error_queries(10) v
147-
JOIN aqo_query_texts t ON (t.query_hash = v.fspace_hash)
146+
"SELECT v.error, t.query_text FROM show_cardinality_errors(false) v
147+
JOIN aqo_query_texts t ON (t.query_hash = v.id)
148148
WHERE v.error > 0.");
149149
note("\n Queries: \n $res \n");
150150
$res = $node->safe_psql('postgres',
151151
"SELECT count(*) FROM top_time_queries(10) v
152152
WHERE v.execution_time > 0.");
153-
is($res, 5);
153+
is($res, 3);
154154

155155
# ##############################################################################
156156
#

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy