mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-25848: record/replay hlindex records_in_range() in optimizer context
check_quick_select_array() now goes through hook_hl_records_in_range(), which records or replaces both the row estimate and the cost (record_hl_records_in_range / infuse_hl_records_in_range). The calls are stored in a new per-table "hl_records_in_range_calls" array. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -197,6 +197,106 @@ let $opt_context_schema=
|
||||
"copy_cost"
|
||||
]
|
||||
}
|
||||
},
|
||||
"records_in_range_calls": {
|
||||
"type": "array",
|
||||
"uniqueItems": false,
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key_number": {
|
||||
"type": "number"
|
||||
},
|
||||
"min_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"max_key": {
|
||||
"type": "string"
|
||||
},
|
||||
"num_records": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"key_number",
|
||||
"min_key",
|
||||
"max_key",
|
||||
"num_records"
|
||||
]
|
||||
}
|
||||
},
|
||||
"hl_records_in_range_calls": {
|
||||
"type": "array",
|
||||
"uniqueItems": false,
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key_number": {
|
||||
"type": "number"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"num_records": {
|
||||
"type": "number"
|
||||
},
|
||||
"cost": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"avg_io_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"cpu_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"comp_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"copy_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"limit_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"setup_cost": {
|
||||
"type": "number"
|
||||
},
|
||||
"index_cost_io": {
|
||||
"type": "number"
|
||||
},
|
||||
"index_cost_cpu": {
|
||||
"type": "number"
|
||||
},
|
||||
"row_cost_io": {
|
||||
"type": "number"
|
||||
},
|
||||
"row_cost_cpu": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"avg_io_cost",
|
||||
"cpu_cost",
|
||||
"comp_cost",
|
||||
"copy_cost",
|
||||
"limit_cost",
|
||||
"setup_cost",
|
||||
"index_cost_io",
|
||||
"index_cost_cpu",
|
||||
"row_cost_io",
|
||||
"row_cost_cpu"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"key_number",
|
||||
"key",
|
||||
"num_records",
|
||||
"cost"
|
||||
]
|
||||
}
|
||||
}
|
||||
"subquery_runs": {
|
||||
"type": "array",
|
||||
|
||||
@@ -278,7 +278,7 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].name');
|
||||
select * from t1 where a > 10;
|
||||
a b
|
||||
Warnings:
|
||||
Warning 4269 Failed to parse saved optimizer context: "name" element not present at offset 1583.
|
||||
Warning 4269 Failed to parse saved optimizer context: "name" element not present at offset 1616.
|
||||
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].ddl');
|
||||
select * from t1 where a > 10;
|
||||
a b
|
||||
@@ -289,7 +289,7 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].file_stat_record
|
||||
select * from t1 where a > 10;
|
||||
a b
|
||||
Warnings:
|
||||
Warning 4269 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1576.
|
||||
Warning 4269 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1609.
|
||||
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].indexes[0].index_name');
|
||||
select * from t1 where a > 10;
|
||||
a b
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Optimizer context record/replay of the ARRAY (hlindex) records_in_range call
|
||||
#
|
||||
set @opt_context_var_name= 'opt_context';
|
||||
create database db1;
|
||||
use db1;
|
||||
CREATE TABLE t1 (
|
||||
id INT PRIMARY KEY,
|
||||
tags JSON NOT NULL,
|
||||
INDEX arr_idx (CAST(tags AS UNSIGNED ARRAY))
|
||||
);
|
||||
INSERT INTO t1 VALUES (1,'[1,2,3]'),(2,'[4,5,6]'),(3,'[3,6,9]'),(4,'[]'),(5,'[7]');
|
||||
set optimizer_record_context=ON;
|
||||
EXPLAIN SELECT id FROM t1 WHERE 3 MEMBER OF (tags);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range arr_idx arr_idx 258 NULL 2 Using where
|
||||
set @opt_context=
|
||||
(select REGEXP_SUBSTR(
|
||||
context,
|
||||
'(?<=set @opt_context=\')([\n\r].*)*(?=\'\;#opt_context_ends)')
|
||||
from information_schema.optimizer_context);
|
||||
set @saved_ctx= @opt_context;
|
||||
set optimizer_record_context=OFF;
|
||||
# The call was recorded, with its cost:
|
||||
select json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].key_number') as key_number,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].key') as k,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].num_records') as num_records,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].cost') is not null as has_cost;
|
||||
key_number k num_records has_cost
|
||||
1 "3" 2 1
|
||||
# Replay with a different row count: EXPLAIN uses it
|
||||
set optimizer_replay_context=@opt_context_var_name;
|
||||
set @opt_context= json_replace(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].num_records', 4);
|
||||
EXPLAIN SELECT id FROM t1 WHERE 3 MEMBER OF (tags);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range arr_idx arr_idx 258 NULL 4 Using where
|
||||
# Replay with an unrecorded value: match-failed warning
|
||||
set @opt_context= @saved_ctx;
|
||||
EXPLAIN SELECT id FROM t1 WHERE 5 MEMBER OF (tags);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range arr_idx arr_idx 258 NULL 1 Using where
|
||||
Warnings:
|
||||
Warning 4270 Failed to match the stats from replay context with the optimizer stats: db1.t1 with key_number:1 with key:5 doesn't exist in hl_records_in_range_calls
|
||||
set optimizer_replay_context='';
|
||||
drop database db1;
|
||||
@@ -0,0 +1,38 @@
|
||||
--source include/not_embedded.inc
|
||||
--disable_replay testfile Dont replay a replay test
|
||||
|
||||
--echo #
|
||||
--echo # Optimizer context record/replay of the ARRAY (hlindex) records_in_range call
|
||||
--echo #
|
||||
set @opt_context_var_name= 'opt_context';
|
||||
create database db1;
|
||||
use db1;
|
||||
CREATE TABLE t1 (
|
||||
id INT PRIMARY KEY,
|
||||
tags JSON NOT NULL,
|
||||
INDEX arr_idx (CAST(tags AS UNSIGNED ARRAY))
|
||||
);
|
||||
INSERT INTO t1 VALUES (1,'[1,2,3]'),(2,'[4,5,6]'),(3,'[3,6,9]'),(4,'[]'),(5,'[7]');
|
||||
|
||||
set optimizer_record_context=ON;
|
||||
EXPLAIN SELECT id FROM t1 WHERE 3 MEMBER OF (tags);
|
||||
--source include/opt_context_save_in_var.inc
|
||||
set @saved_ctx= @opt_context;
|
||||
set optimizer_record_context=OFF;
|
||||
|
||||
--echo # The call was recorded, with its cost:
|
||||
select json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].key_number') as key_number,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].key') as k,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].num_records') as num_records,
|
||||
json_extract(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].cost') is not null as has_cost;
|
||||
|
||||
--echo # Replay with a different row count: EXPLAIN uses it
|
||||
set optimizer_replay_context=@opt_context_var_name;
|
||||
set @opt_context= json_replace(@saved_ctx, '$.tables[0].hl_records_in_range_calls[0].num_records', 4);
|
||||
EXPLAIN SELECT id FROM t1 WHERE 3 MEMBER OF (tags);
|
||||
|
||||
--echo # Replay with an unrecorded value: match-failed warning
|
||||
set @opt_context= @saved_ctx;
|
||||
EXPLAIN SELECT id FROM t1 WHERE 5 MEMBER OF (tags);
|
||||
set optimizer_replay_context='';
|
||||
drop database db1;
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "set_var.h"
|
||||
#include "sql_class.h"
|
||||
#include "opt_context_store_replay.h"
|
||||
#include "index/hlindex.h" // hlindex (TABLE::hli)
|
||||
#include "sql_show.h"
|
||||
#include "my_json_writer.h"
|
||||
#include "hash.h"
|
||||
@@ -164,6 +165,23 @@ public:
|
||||
String *err_buf);
|
||||
};
|
||||
|
||||
/*
|
||||
A record to hold one hlindex records_in_range() call (ARRAY keys):
|
||||
*/
|
||||
class hl_records_in_range_call_record : public Sql_alloc
|
||||
{
|
||||
public:
|
||||
uint keynr;
|
||||
char *key;
|
||||
ha_rows records;
|
||||
Cost_estimate cost;
|
||||
|
||||
static
|
||||
hl_records_in_range_call_record* parse(MEM_ROOT *mem_root,
|
||||
json_engine_t *je,
|
||||
String *err_buf);
|
||||
};
|
||||
|
||||
/*
|
||||
structure to store all the index range records,
|
||||
and the cost for reading indexes, pertaining to a table
|
||||
@@ -177,6 +195,7 @@ public:
|
||||
List<Multi_range_read_const_call_record> mrr_list;
|
||||
List<cost_index_read_call_record> irc_list;
|
||||
List<records_in_range_call_record> rir_list;
|
||||
List<hl_records_in_range_call_record> hl_rir_list;
|
||||
List<char> const_tbl_ins_stmt_list;
|
||||
};
|
||||
|
||||
@@ -243,6 +262,22 @@ static bool is_base_table(const TABLE_LIST *tbl)
|
||||
tbl->table->s->tmp_table != SYSTEM_TMP_TABLE);
|
||||
}
|
||||
|
||||
static void dump_cost_estimate(const Cost_estimate *cost,
|
||||
Json_writer *ctx_writer)
|
||||
{
|
||||
Json_writer_object obj(ctx_writer, "cost");
|
||||
obj.add("avg_io_cost", cost->avg_io_cost);
|
||||
obj.add("cpu_cost", cost->cpu_cost);
|
||||
obj.add("comp_cost", cost->comp_cost);
|
||||
obj.add("copy_cost", cost->copy_cost);
|
||||
obj.add("limit_cost", cost->limit_cost);
|
||||
obj.add("setup_cost", cost->setup_cost);
|
||||
obj.add("index_cost_io", cost->index_cost.io);
|
||||
obj.add("index_cost_cpu", cost->index_cost.cpu);
|
||||
obj.add("row_cost_io", cost->row_cost.io);
|
||||
obj.add("row_cost_cpu", cost->row_cost.cpu);
|
||||
}
|
||||
|
||||
static
|
||||
void dump_mrr_info_calls(List<Multi_range_read_const_call_record> *mrr_list,
|
||||
Json_writer *ctx_writer)
|
||||
@@ -263,19 +298,7 @@ void dump_mrr_info_calls(List<Multi_range_read_const_call_record> *mrr_list,
|
||||
}
|
||||
|
||||
irc_wrapper.add("num_rows", irc->rows);
|
||||
{
|
||||
Json_writer_object obj(ctx_writer, "cost");
|
||||
obj.add("avg_io_cost", irc->cost.avg_io_cost);
|
||||
obj.add("cpu_cost", irc->cost.cpu_cost);
|
||||
obj.add("comp_cost", irc->cost.comp_cost);
|
||||
obj.add("copy_cost", irc->cost.copy_cost);
|
||||
obj.add("limit_cost", irc->cost.limit_cost);
|
||||
obj.add("setup_cost", irc->cost.setup_cost);
|
||||
obj.add("index_cost_io", irc->cost.index_cost.io);
|
||||
obj.add("index_cost_cpu", irc->cost.index_cost.cpu);
|
||||
obj.add("row_cost_io", irc->cost.row_cost.io);
|
||||
obj.add("row_cost_cpu", irc->cost.row_cost.cpu);
|
||||
}
|
||||
dump_cost_estimate(&irc->cost, ctx_writer);
|
||||
irc_wrapper.add("mrr_mode", irc->mrr_mode);
|
||||
|
||||
irc_wrapper.add("max_index_blocks", irc->max_index_blocks);
|
||||
@@ -325,6 +348,23 @@ void dump_records_in_range_calls(List<records_in_range_call_record> *rir_list,
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void dump_hl_records_in_range_calls(
|
||||
List<hl_records_in_range_call_record> *list, Json_writer *ctx_writer)
|
||||
{
|
||||
Json_writer_array wrapper(ctx_writer, "hl_records_in_range_calls");
|
||||
List_iterator li(*list);
|
||||
|
||||
while (hl_records_in_range_call_record *rec= li++)
|
||||
{
|
||||
Json_writer_object obj(ctx_writer);
|
||||
obj.add("key_number", rec->keynr);
|
||||
obj.add("key", rec->key);
|
||||
obj.add("num_records", rec->records);
|
||||
dump_cost_estimate(&rec->cost, ctx_writer);
|
||||
}
|
||||
}
|
||||
|
||||
void Optimizer_context_recorder::dump_recorded_table_calls(
|
||||
table_context_for_store *tbl,
|
||||
Json_writer *writer)
|
||||
@@ -332,6 +372,7 @@ void Optimizer_context_recorder::dump_recorded_table_calls(
|
||||
dump_mrr_info_calls(&tbl->mrr_list, writer);
|
||||
dump_index_read_calls(&tbl->irc_list, writer);
|
||||
dump_records_in_range_calls(&tbl->rir_list, writer);
|
||||
dump_hl_records_in_range_calls(&tbl->hl_rir_list, writer);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1155,6 +1196,30 @@ void Optimizer_context_recorder::record_records_in_range(
|
||||
table_ctx->rir_list.push_back(rec_in_range_ctx, mem_root);
|
||||
}
|
||||
|
||||
void Optimizer_context_recorder::record_hl_records_in_range(
|
||||
const TABLE *tbl, uint keynr, const uchar *value, size_t value_len,
|
||||
ha_rows records, const Cost_estimate *cost)
|
||||
{
|
||||
auto *rec= new (mem_root) hl_records_in_range_call_record;
|
||||
if (unlikely(!rec))
|
||||
return; // OOM
|
||||
|
||||
rec->keynr= keynr;
|
||||
StringBuffer<128> key(system_charset_info);
|
||||
tbl->hli->print_key(&key, value, value_len);
|
||||
if (!(rec->key= strdup_root(mem_root, &key)))
|
||||
return; // OOM
|
||||
|
||||
rec->records= records;
|
||||
rec->cost= *cost;
|
||||
|
||||
table_context_for_store *table_ctx= get_table_context(tbl);
|
||||
if (unlikely(!table_ctx))
|
||||
return; // OOM
|
||||
|
||||
table_ctx->hl_rir_list.push_back(rec, mem_root);
|
||||
}
|
||||
|
||||
void Optimizer_context_recorder::record_table_row(TABLE *tbl, int row_index)
|
||||
{
|
||||
StringBuffer<512> output(&my_charset_utf8mb4_bin);
|
||||
@@ -1267,6 +1332,7 @@ public:
|
||||
List<Multi_range_read_const_call_record> ranges_list;
|
||||
List<cost_index_read_call_record> irc_list;
|
||||
List<records_in_range_call_record> rir_list;
|
||||
List<hl_records_in_range_call_record> hl_rir_list;
|
||||
|
||||
static
|
||||
table_context_for_replay *parse(MEM_ROOT *mem_root, json_engine_t *je,
|
||||
@@ -1410,6 +1476,11 @@ table_context_for_replay::parse(MEM_ROOT *mem_root, json_engine_t *je,
|
||||
Read_object_array<records_in_range_call_record>(
|
||||
mem_root, &table_ctx->rir_list, records_in_range_call_record::parse),
|
||||
true},
|
||||
{"hl_records_in_range_calls",
|
||||
Read_object_array<hl_records_in_range_call_record>(
|
||||
mem_root, &table_ctx->hl_rir_list,
|
||||
hl_records_in_range_call_record::parse),
|
||||
true},
|
||||
{NULL, Read_double(NULL), true}
|
||||
};
|
||||
|
||||
@@ -1620,6 +1691,29 @@ records_in_range_call_record::parse(MEM_ROOT *mem_root,
|
||||
return out;
|
||||
}
|
||||
|
||||
hl_records_in_range_call_record*
|
||||
hl_records_in_range_call_record::parse(MEM_ROOT *mem_root,
|
||||
json_engine_t *je,
|
||||
String *err_buf)
|
||||
{
|
||||
auto out= new (mem_root) hl_records_in_range_call_record;
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
Read_named_member members[]=
|
||||
{
|
||||
{"key_number", Read_non_neg_integer<uint, UINT_MAX>(&out->keynr), false},
|
||||
{"key", Read_string(mem_root, &out->key), false},
|
||||
{"num_records",
|
||||
Read_non_neg_integer<ha_rows, ULONGLONG_MAX>(&out->records), false},
|
||||
{"cost", Read_range_cost_estimate(mem_root, &out->cost), false},
|
||||
{NULL, Read_double(NULL), true}
|
||||
};
|
||||
if (json_read_object(je, members, err_buf))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
Optimizer_context_replay::Optimizer_context_replay(THD *thd_arg) : thd(thd_arg)
|
||||
{
|
||||
parse(); // TODO: error handling?
|
||||
@@ -2007,6 +2101,47 @@ bool Optimizer_context_replay::infuse_records_in_range(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer_context_replay::infuse_hl_records_in_range(
|
||||
const TABLE *tbl, uint keynr, const uchar *value, size_t value_len,
|
||||
ha_rows *records, Cost_estimate *cost)
|
||||
{
|
||||
if (!has_records() || !is_base_table(tbl->pos_in_table_list))
|
||||
return true;
|
||||
|
||||
StringBuffer<128> key(system_charset_info);
|
||||
String tbl_name;
|
||||
tbl->hli->print_key(&key, value, value_len);
|
||||
append_base_table_name(tbl, &tbl_name);
|
||||
|
||||
if (table_context_for_replay *tbl_ctx=
|
||||
find_table_context(tbl_name.c_ptr_safe()))
|
||||
{
|
||||
List_iterator<hl_records_in_range_call_record> iter(tbl_ctx->hl_rir_list);
|
||||
while (hl_records_in_range_call_record *rec= iter++)
|
||||
{
|
||||
if (rec->keynr == keynr && !strcmp(rec->key, key.c_ptr_safe()))
|
||||
{
|
||||
*records= rec->records;
|
||||
*cost= rec->cost;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String warn_msg(256);
|
||||
warn_msg.append(tbl_name);
|
||||
warn_msg.append(STRING_WITH_LEN(" with key_number:"));
|
||||
warn_msg.append_ulonglong(keynr);
|
||||
warn_msg.append(STRING_WITH_LEN(" with key:"));
|
||||
warn_msg.append(key);
|
||||
push_warning_printf(
|
||||
thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_JSON_OPTIMIZER_REPLAY_CONTEXT_MATCH_FAILED,
|
||||
ER_THD(thd, ER_JSON_OPTIMIZER_REPLAY_CONTEXT_MATCH_FAILED),
|
||||
warn_msg.c_ptr_safe(), "hl_records_in_range_calls");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@brief
|
||||
restore the saved stats for the tables, and indexes that were
|
||||
|
||||
@@ -78,6 +78,9 @@ public:
|
||||
const KEY_PART_INFO *key_part, uint keynr,
|
||||
const key_range *min_range,
|
||||
const key_range *max_range, ha_rows records);
|
||||
void record_hl_records_in_range(const TABLE *tbl, uint keynr,
|
||||
const uchar *value, size_t value_len,
|
||||
ha_rows records, const Cost_estimate *cost);
|
||||
void record_current_table_row(TABLE *tbl)
|
||||
{
|
||||
/* use table->record[0] */
|
||||
@@ -212,6 +215,9 @@ public:
|
||||
bool infuse_records_in_range(const TABLE *tbl, const KEY_PART_INFO *key_part,
|
||||
uint keynr, const key_range *min_range,
|
||||
const key_range *max_range, ha_rows *records);
|
||||
bool infuse_hl_records_in_range(const TABLE *tbl, uint keynr,
|
||||
const uchar *value, size_t value_len,
|
||||
ha_rows *records, Cost_estimate *cost);
|
||||
|
||||
private:
|
||||
THD *thd;
|
||||
|
||||
@@ -489,6 +489,9 @@ static ha_rows hook_records_in_range(MEM_ROOT *mem_root, THD *thd,
|
||||
const key_range *min_range,
|
||||
const key_range *max_range,
|
||||
page_range *pages);
|
||||
static ha_rows hook_hl_records_in_range(THD *thd, TABLE *table, uint keynr,
|
||||
const uchar *value, size_t value_len,
|
||||
Cost_estimate *cost);
|
||||
|
||||
/*
|
||||
SEL_IMERGE is a list of possible ways to do index merge, i.e. it is
|
||||
@@ -12654,10 +12657,9 @@ ha_rows check_quick_select_array(PARAM *param, uint keynr, SEL_ARG *tree,
|
||||
if (param->table->hlindex_open(keynr) || param->table->hlindex_lock(keynr))
|
||||
return HA_POS_ERROR;
|
||||
|
||||
rows= param->table->hli->records_in_range(param->table,
|
||||
param->table->key_info + keynr,
|
||||
tree->min_value,
|
||||
JSON_INDEX_KEY_MAX_LEN, cost);
|
||||
rows= hook_hl_records_in_range(param->thd, param->table, keynr,
|
||||
tree->min_value, JSON_INDEX_KEY_MAX_LEN,
|
||||
cost);
|
||||
param->quick_rows[keynr]= rows;
|
||||
if (rows == HA_POS_ERROR)
|
||||
return HA_POS_ERROR;
|
||||
@@ -18157,3 +18159,30 @@ static ha_rows hook_records_in_range(MEM_ROOT *mem_root, THD *thd,
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@brief
|
||||
Call hli->records_in_range(). If necessary,
|
||||
- Replace its return value and cost from Optimizer Context, and/or
|
||||
- Save them in the Optimizer Context we're recording.
|
||||
|
||||
@detail
|
||||
This is the hlindex counterpart of hook_records_in_range().
|
||||
*/
|
||||
static ha_rows hook_hl_records_in_range(THD *thd, TABLE *table, uint keynr,
|
||||
const uchar *value, size_t value_len,
|
||||
Cost_estimate *cost)
|
||||
{
|
||||
ha_rows records= table->hli->records_in_range(table, table->key_info + keynr,
|
||||
value, value_len, cost);
|
||||
|
||||
if (Optimizer_context_replay *repl= thd->opt_ctx_replay)
|
||||
repl->infuse_hl_records_in_range(table, keynr, value, value_len, &records,
|
||||
cost);
|
||||
|
||||
if (Optimizer_context_recorder *recorder= thd->opt_ctx_recorder)
|
||||
recorder->record_hl_records_in_range(table, keynr, value, value_len,
|
||||
records, cost);
|
||||
return records;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user