Skip to content

Commit 491ded1

Browse files
MDEV-36511: Dump basic stats of a table to trace
This feature stores the basic stats of the base tables that are used in a query, to the optimizer trace. This feature is also controlled by optimizer_record_context, and is not enabled by default. The stats such as num_of_records present in the table, indexes if present then their names, along with the average number of records_per_key with in each index are dumped to the trace. Additionally, stats from range analysis of the queries are also dumped into the trace The approach taken here is to extend the existing function store_tables_context_in_trace() and add new dump_table_stats_to_trace() to opt_trace_ddl_info.cc. For storing the range analysis stats into the trace, they are first recorded in the hash defined in Optimizer_Stats_Context_Recorder, and is used later while dumping the stats into the trace from dump_table_stats_to_trace(). Several new tests are also added to opt_trace_store_stats.test
1 parent db937cc commit 491ded1

11 files changed

+824
-43
lines changed
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
#enable both optimizer_trace, and optimizer_record_context
2+
set optimizer_record_context=ON;
3+
set optimizer_trace=1;
4+
create database db1;
5+
use db1;
6+
create table t1
7+
(
8+
a int, b int,
9+
index t1_idx_a (a),
10+
index t1_idx_b (b),
11+
index t1_idx_ab (a, b)
12+
);
13+
insert into t1 select seq%2, seq%3 from seq_1_to_20;
14+
create table t2 (
15+
a int,
16+
index t2_idx_a (a)
17+
);
18+
insert into t2 select seq%6 from seq_1_to_30;
19+
create view view1 as (
20+
select t1.a as a, t1.b as b, t2.a as c from (t1 join t2) where t1.a = t2.a and t1.a = 5
21+
);
22+
# analyze all the tables
23+
set session use_stat_tables='COMPLEMENTARY';
24+
analyze table t1 persistent for all;
25+
Table Op Msg_type Msg_text
26+
db1.t1 analyze status Engine-independent statistics collected
27+
db1.t1 analyze status Table is already up to date
28+
analyze table t2 persistent for all;
29+
Table Op Msg_type Msg_text
30+
db1.t2 analyze status Engine-independent statistics collected
31+
db1.t2 analyze status Table is already up to date
32+
#
33+
# simple query using one table
34+
#
35+
select count(*) from t1;
36+
count(*)
37+
20
38+
set @trace= (select trace from information_schema.optimizer_trace);
39+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
40+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
41+
num_of_records
42+
0
43+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
44+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
45+
index_name rec_per_key
46+
t1_idx_a ["10"]
47+
t1_idx_b ["7"]
48+
t1_idx_ab [
49+
"10",
50+
"3"
51+
]
52+
#
53+
# simple query using join of two tables
54+
#
55+
select count(*) from t1, t2 where t1.a = t2.a;
56+
count(*)
57+
100
58+
set @trace= (select trace from information_schema.optimizer_trace);
59+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
60+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
61+
num_of_records
62+
30
63+
20
64+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
65+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
66+
index_name rec_per_key
67+
t2_idx_a ["5"]
68+
t1_idx_a ["10"]
69+
t1_idx_b ["7"]
70+
t1_idx_ab [
71+
"10",
72+
"3"
73+
]
74+
#
75+
# negative test
76+
# simple query using join of two tables
77+
# there should be no result
78+
#
79+
set optimizer_record_context=OFF;
80+
select count(*) from t1, t2 where t1.a = t2.a;
81+
count(*)
82+
100
83+
set @trace= (select trace from information_schema.optimizer_trace);
84+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
85+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
86+
num_of_records
87+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
88+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
89+
index_name rec_per_key
90+
set optimizer_record_context=ON;
91+
#
92+
# there should be no duplicate information
93+
#
94+
select * from view1 union select * from view1;
95+
a b c
96+
set @trace= (select trace from information_schema.optimizer_trace);
97+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
98+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
99+
num_of_records
100+
30
101+
20
102+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
103+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
104+
index_name rec_per_key
105+
t2_idx_a ["5"]
106+
t1_idx_a ["10"]
107+
t1_idx_b ["7"]
108+
t1_idx_ab [
109+
"10",
110+
"3"
111+
]
112+
#
113+
# test for update
114+
#
115+
update t1 set t1.b = t1.a;
116+
analyze table t1 persistent for all;
117+
Table Op Msg_type Msg_text
118+
db1.t1 analyze status Engine-independent statistics collected
119+
db1.t1 analyze status OK
120+
set @trace= (select trace from information_schema.optimizer_trace);
121+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
122+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
123+
num_of_records
124+
20
125+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
126+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
127+
index_name rec_per_key
128+
t1_idx_a ["10"]
129+
t1_idx_b ["7"]
130+
t1_idx_ab [
131+
"10",
132+
"3"
133+
]
134+
#
135+
# test for insert as select
136+
#
137+
insert into t1 (select t2.a as a, t2.a as b from t2);
138+
analyze table t1 persistent for all;
139+
Table Op Msg_type Msg_text
140+
db1.t1 analyze status Engine-independent statistics collected
141+
db1.t1 analyze status OK
142+
set @trace= (select trace from information_schema.optimizer_trace);
143+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
144+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
145+
num_of_records
146+
30
147+
20
148+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
149+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
150+
index_name rec_per_key
151+
t2_idx_a ["5"]
152+
t1_idx_a ["10"]
153+
t1_idx_b ["10"]
154+
t1_idx_ab [
155+
"10",
156+
"10"
157+
]
158+
#
159+
# range analysis tests
160+
#
161+
#
162+
# simple query with or condition on 2 columns
163+
#
164+
analyze select * from t1 where t1.a between 1 and 5 or t1.b between 6 and 10;
165+
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
166+
1 SIMPLE t1 index t1_idx_a,t1_idx_b,t1_idx_ab t1_idx_ab 10 NULL 50 50.00 100.00 70.00 Using where; Using index
167+
set @trace= (select trace from information_schema.optimizer_trace);
168+
set @list_ranges= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.list_ranges')));
169+
select * from json_table(
170+
@list_ranges,
171+
'$[*][*]' columns(
172+
index_name text path '$.index_name',
173+
ranges json path '$.ranges',
174+
num_rows int path '$.num_rows'
175+
)
176+
) as jt;
177+
index_name ranges num_rows
178+
t1_idx_a ["(1) <= (a) <= (5)"] 35
179+
t1_idx_ab ["(1) <= (a) <= (5)"] 35
180+
t1_idx_b ["(6) <= (b) <= (10)"] 1
181+
#
182+
# simple query with or condition on the same column
183+
#
184+
analyze select * from t1 where t1.a between 1 and 5 or t1.a between 6 and 10;
185+
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
186+
1 SIMPLE t1 range t1_idx_a,t1_idx_ab t1_idx_ab 5 NULL 36 35.00 100.00 100.00 Using where; Using index
187+
set @trace= (select trace from information_schema.optimizer_trace);
188+
set @list_ranges= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.list_ranges')));
189+
select * from json_table(
190+
@list_ranges,
191+
'$[*][*]' columns(
192+
index_name text path '$.index_name',
193+
ranges json path '$.ranges',
194+
num_rows int path '$.num_rows'
195+
)
196+
) as jt;
197+
index_name ranges num_rows
198+
t1_idx_a [
199+
"(1) <= (a) <= (5)",
200+
"(6) <= (a) <= (10)"
201+
] 36
202+
t1_idx_ab [
203+
"(1) <= (a) <= (5)",
204+
"(6) <= (a) <= (10)"
205+
] 36
206+
#
207+
# negative test on the simple query with or condition on 2 columns
208+
#
209+
set optimizer_record_context=OFF;
210+
analyze select * from t1 where t1.a between 1 and 5 or t1.b between 6 and 10;
211+
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
212+
1 SIMPLE t1 index t1_idx_a,t1_idx_b,t1_idx_ab t1_idx_ab 10 NULL 50 50.00 100.00 70.00 Using where; Using index
213+
set @trace= (select trace from information_schema.optimizer_trace);
214+
set @list_ranges= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.list_ranges')));
215+
select * from json_table(
216+
@list_ranges,
217+
'$[*][*]' columns(
218+
index_name text path '$.index_name',
219+
ranges json path '$.ranges',
220+
num_rows int path '$.num_rows'
221+
)
222+
) as jt;
223+
index_name ranges num_rows
224+
set optimizer_record_context=ON;
225+
#
226+
# simple query with or condition on 2 columns
227+
# testing all the stats information
228+
#
229+
analyze select * from t1 where t1.a between 1 and 5 or t1.b between 6 and 10;
230+
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
231+
1 SIMPLE t1 index t1_idx_a,t1_idx_b,t1_idx_ab t1_idx_ab 10 NULL 50 50.00 100.00 70.00 Using where; Using index
232+
set @trace= (select trace from information_schema.optimizer_trace);
233+
set @records= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.num_of_records')));
234+
select * from json_table(@records, '$[*]' columns(num_of_records text path '$')) as jt;
235+
num_of_records
236+
50
237+
set @indexes=(select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.indexes')));
238+
select * from json_table(@indexes, '$[*][*]' columns(index_name text path '$.index_name', rec_per_key json path '$.rec_per_key')) as jt;
239+
index_name rec_per_key
240+
t1_idx_a ["8"]
241+
t1_idx_b ["8"]
242+
t1_idx_ab [
243+
"8",
244+
"8"
245+
]
246+
set @list_ranges= (select JSON_DETAILED(JSON_EXTRACT(@trace, '$**.list_ranges')));
247+
select * from json_table(
248+
@list_ranges,
249+
'$[*][*]' columns(
250+
index_name text path '$.index_name',
251+
ranges json path '$.ranges',
252+
num_rows int path '$.num_rows'
253+
)
254+
) as jt;
255+
index_name ranges num_rows
256+
t1_idx_a ["(1) <= (a) <= (5)"] 35
257+
t1_idx_ab ["(1) <= (a) <= (5)"] 35
258+
t1_idx_b ["(6) <= (b) <= (10)"] 1
259+
drop view view1;
260+
drop table t1;
261+
drop table t2;
262+
drop database db1;

0 commit comments

Comments
 (0)