Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 14 additions & 9 deletions mysql-test/main/opt_context_load_stats_basic.result
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].name');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "name" element not present at offset 1387.
Warning 4253 Failed to parse saved optimizer context: "name" element not present at offset 1441.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].ddl');
select * from t1 where a > 10;
a b
Expand All @@ -354,12 +354,12 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].file_stat
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1380.
Warning 4253 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1434.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].file_stat_records');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1380.
Warning 4253 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1434.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].indexes[0].index_name');
select * from t1 where a > 10;
a b
Expand All @@ -374,32 +374,37 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_rang
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "index_name" element not present at offset 621.
Warning 4253 Failed to parse saved optimizer context: "index_name" element not present at offset 639.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].ranges');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "ranges" element not present at offset 613.
Warning 4253 Failed to parse saved optimizer context: "ranges" element not present at offset 631.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].num_rows');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "num_rows" element not present at offset 631.
Warning 4253 Failed to parse saved optimizer context: "num_rows" element not present at offset 649.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].cost');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "cost" element not present at offset 415.
Warning 4253 Failed to parse saved optimizer context: "cost" element not present at offset 433.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].max_index_blocks');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 624.
Warning 4253 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 642.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].max_row_blocks');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 626.
Warning 4253 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 644.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].call_number');
select * from t1 where a > 10;
a b
Warnings:
Warning 4253 Failed to parse saved optimizer context: "call_number" element not present at offset 647.
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].indexes[0]');
select * from t1 where a > 10;
a b
Expand Down
3 changes: 3 additions & 0 deletions mysql-test/main/opt_context_load_stats_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ select * from t1 where a > 10;
set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].max_row_blocks');
select * from t1 where a > 10;

set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].list_ranges[0].call_number');
select * from t1 where a > 10;

set @opt_context=json_remove(@saved_opt_context_1, '$.list_contexts[0].indexes[0]');
select * from t1 where a > 10;

Expand Down
126 changes: 126 additions & 0 deletions mysql-test/main/opt_context_replay_basic.result
Original file line number Diff line number Diff line change
Expand Up @@ -409,4 +409,130 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL btn NULL NULL NULL 4 Using where
set optimizer_replay_context='';
drop table t1;
#
# MDEV-39538: Different cost when same rangeis read twice
#
create table t1 (pk int primary key, a datetime, c int, key(a));
insert into t1 (pk,a,c) values (1,'2009-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (2,'2009-11-29 03:23:32', 2);
insert into t1 (pk,a,c) values (3,'2009-10-16 05:56:32', 2);
insert into t1 (pk,a,c) values (4,'2010-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (5,'2010-10-16 05:56:32', 2);
insert into t1 (pk,a,c) values (6,'2011-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (7,'2012-10-16 05:56:32', 2);
set optimizer_record_context=1;
explain format=json select * from t1
where year(a) = 2010 and c < (select count(*) from t1 where year(a) = 2010);
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost": 0.003808422,
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["a"],
"key": "a",
"key_length": "6",
"used_key_parts": ["a"],
"loops": 1,
"rows": 2,
"cost": 0.003808422,
"filtered": 100,
"index_condition": "t1.a between '2010-01-01 00:00:00' and '2010-12-31 23:59:59'",
"attached_condition": "t1.c < (subquery#2)"
}
}
],
"subqueries": [
{
"query_block": {
"select_id": 2,
"cost": 0.001617224,
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["a"],
"key": "a",
"key_length": "6",
"used_key_parts": ["a"],
"loops": 1,
"rows": 2,
"cost": 0.001617224,
"filtered": 100,
"attached_condition": "t1.a between '2010-01-01 00:00:00' and '2010-12-31 23:59:59'",
"using_index": true
}
}
]
}
}
]
}
}
select context into dumpfile "../../tmp/dump1.sql"
from information_schema.optimizer_context;
set optimizer_record_context=0;
drop table t1;
set optimizer_replay_context='opt_context';
# Same query as above, must have same explain cost:
explain format=json select * from t1
where year(a) = 2010 and c < (select count(*) from t1 where year(a) = 2010);
EXPLAIN
{
"query_block": {
"select_id": 1,
"cost": 0.003808422,
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["a"],
"key": "a",
"key_length": "6",
"used_key_parts": ["a"],
"loops": 1,
"rows": 2,
"cost": 0.003808422,
"filtered": 100,
"index_condition": "t1.a between '2010-01-01 00:00:00' and '2010-12-31 23:59:59'",
"attached_condition": "t1.c < (subquery#2)"
}
}
],
"subqueries": [
{
"query_block": {
"select_id": 2,
"cost": 0.001617224,
"nested_loop": [
{
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["a"],
"key": "a",
"key_length": "6",
"used_key_parts": ["a"],
"loops": 1,
"rows": 2,
"cost": 0.001617224,
"filtered": 100,
"attached_condition": "t1.a between '2010-01-01 00:00:00' and '2010-12-31 23:59:59'",
"using_index": true
}
}
]
}
}
]
}
}
set optimizer_replay_context='';
drop table t1;
drop database db1;
35 changes: 35 additions & 0 deletions mysql-test/main/opt_context_replay_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,39 @@ set optimizer_replay_context='';
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
drop table t1;

--echo #
--echo # MDEV-39538: Different cost when same rangeis read twice
--echo #
create table t1 (pk int primary key, a datetime, c int, key(a));

insert into t1 (pk,a,c) values (1,'2009-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (2,'2009-11-29 03:23:32', 2);
insert into t1 (pk,a,c) values (3,'2009-10-16 05:56:32', 2);
insert into t1 (pk,a,c) values (4,'2010-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (5,'2010-10-16 05:56:32', 2);
insert into t1 (pk,a,c) values (6,'2011-11-29 13:43:32', 2);
insert into t1 (pk,a,c) values (7,'2012-10-16 05:56:32', 2);

set optimizer_record_context=1;
explain format=json select * from t1
where year(a) = 2010 and c < (select count(*) from t1 where year(a) = 2010);
select context into dumpfile "../../tmp/dump1.sql"
from information_schema.optimizer_context;
set optimizer_record_context=0;
drop table t1;
--disable_query_log
--disable_result_log
--source "$MYSQLTEST_VARDIR/tmp/dump1.sql"
--enable_query_log
--enable_result_log
set optimizer_replay_context='opt_context';
--echo # Same query as above, must have same explain cost:
explain format=json select * from t1
where year(a) = 2010 and c < (select count(*) from t1 where year(a) = 2010);

set optimizer_replay_context='';
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
drop table t1;


drop database db1;
13 changes: 11 additions & 2 deletions sql/opt_context_store_replay.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class Multi_range_read_const_call_record : public Sql_alloc
Cost_estimate cost;
ha_rows max_index_blocks;
ha_rows max_row_blocks;
ulong call_number;
};

/*
Expand Down Expand Up @@ -257,6 +258,7 @@ void dump_mrr_info_calls(List<Multi_range_read_const_call_record> *mrr_list,

irc_wrapper.add("max_index_blocks", irc->max_index_blocks);
irc_wrapper.add("max_row_blocks", irc->max_row_blocks);
irc_wrapper.add("call_number", irc->call_number);
}
}

Expand Down Expand Up @@ -818,11 +820,13 @@ void Optimizer_context_recorder::record_multi_range_read_info_const(
if (current_thd->lex->explain->is_query_plan_ready())
return;

mrr_counter++;
auto *range_ctx= new (mem_root) Multi_range_read_const_call_record;

if (unlikely(!range_ctx))
return; // OOM
Comment thread
bsrikanth-mariadb marked this conversation as resolved.

range_ctx->call_number= mrr_counter;
const char *index_name= tbl->table->key_info[keynr].name.str;
if (!(range_ctx->idx_name= strdup_root(mem_root, index_name)))
return; // OOM
Expand Down Expand Up @@ -1285,8 +1289,7 @@ static int parse_range_context(MEM_ROOT *mem_root, json_engine_t *je, String *er
Read_named_member array[]= {
{"index_name", Read_string(mem_root, &out->idx_name), false},
{"ranges", Read_array_of_strings(mem_root, &out->range_list), false},
{"num_rows",
Read_non_neg_integer<ha_rows, ULONGLONG_MAX>(&out->rows),
{"num_rows", Read_non_neg_integer<ha_rows, ULONGLONG_MAX>(&out->rows),
false},
{"cost", Read_range_cost_estimate(mem_root, &out->cost), false},
{"max_index_blocks",
Expand All @@ -1295,6 +1298,8 @@ static int parse_range_context(MEM_ROOT *mem_root, json_engine_t *je, String *er
{"max_row_blocks",
Read_non_neg_integer<ha_rows, ULONGLONG_MAX>(&out->max_row_blocks),
false},
{"call_number",
Read_non_neg_integer<ulong, ULONG_MAX>(&out->call_number), false},
{NULL, Read_double(NULL), true}};

return parse_context_obj_from_json_array(je, err_buf, err_msg, array);
Expand Down Expand Up @@ -1516,6 +1521,7 @@ bool Optimizer_context_replay::infuse_range_stats(
if (!has_records() || !is_base_table(table->pos_in_table_list))
return true;

mrr_counter++;
KEY *keyinfo= table->key_info + keynr;
const char *idx_name= keyinfo->name.str;
const KEY_PART_INFO *key_part= keyinfo->key_part;
Expand Down Expand Up @@ -1544,6 +1550,9 @@ bool Optimizer_context_replay::infuse_range_stats(
List_iterator<Multi_range_read_const_call_record> range_ctx_itr(mrr_const_calls);
while (Multi_range_read_const_call_record *range_ctx= range_ctx_itr++)
{
if (range_ctx->call_number != mrr_counter)
continue;

List_iterator<char> range_itr(range_ctx->range_list);
seq_it= seq_if->init((void *) seq, 0, 0);
bool matched= true;
Expand Down
9 changes: 8 additions & 1 deletion sql/opt_context_store_replay.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,12 @@ class Optimizer_context_recorder
table_context_for_store *get_table_context(const TABLE_LIST *tbl);
static const uchar *get_tbl_ctx_key(const void *entry_, size_t *length,
my_bool flags);
/*
counter that tracks record_multi_range_read_info_const() calls
*/
ulong mrr_counter= 0;
};


/* Save the collected context into optimizer_context IS table */
bool store_optimizer_context(THD *thd);

Expand Down Expand Up @@ -150,6 +153,10 @@ class Optimizer_context_replay
bool infuse_table_rows(const TABLE *tbl, ha_rows *rows);

THD *thd;
/*
counter that tracks infuse_range_stats() calls
*/
ulong mrr_counter= 0;
/*
Statistics that tables had before we've replaced them with values from
the saved context. To be used to restore the original values.
Expand Down
Loading