mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
EXPLAIN FORMAT=JSON: produce used_key_parts, JSON-ish output for index_merge.
This commit is contained in:
@ -38,13 +38,14 @@ EXPLAIN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Try a basic join
|
||||||
create table t1 (a int, b int, filler char(32), key(a));
|
create table t1 (a int, b int, filler char(32), key(a));
|
||||||
insert into t1
|
insert into t1
|
||||||
select
|
select
|
||||||
A.a + B.a* 10 + C.a * 100,
|
a.a + b.a* 10 + c.a * 100,
|
||||||
A.a + B.a* 10 + C.a * 100,
|
a.a + b.a* 10 + c.a * 100,
|
||||||
'filler'
|
'filler'
|
||||||
from t0 A, t0 B, t0 C;
|
from t0 a, t0 b, t0 c;
|
||||||
explain format=json select * from t0,t1 where t1.a=t0.a;
|
explain format=json select * from t0,t1 where t1.a=t0.a;
|
||||||
EXPLAIN
|
EXPLAIN
|
||||||
{
|
{
|
||||||
@ -62,12 +63,116 @@ EXPLAIN
|
|||||||
"access_type": "ref",
|
"access_type": "ref",
|
||||||
"possible_keys": ["a"],
|
"possible_keys": ["a"],
|
||||||
"key": "a",
|
"key": "a",
|
||||||
"used_key_parts": "TODO",
|
|
||||||
"key_length": "5",
|
"key_length": "5",
|
||||||
|
"used_key_parts": ["a"],
|
||||||
"ref": ["test.t0.a"],
|
"ref": ["test.t0.a"],
|
||||||
"rows": 1,
|
"rows": 1,
|
||||||
"filtered": 100
|
"filtered": 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Try range and index_merge
|
||||||
|
create table t2 (a1 int, a2 int, b1 int, b2 int, key(a1,a2), key(b1,b2));
|
||||||
|
insert into t2 select a,a,a,a from t1;
|
||||||
|
explain format=json select * from t2 where a1<5;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "range",
|
||||||
|
"possible_keys": ["a1"],
|
||||||
|
"key": "a1",
|
||||||
|
"key_length": "5",
|
||||||
|
"used_key_parts": ["a1"],
|
||||||
|
"rows": 5,
|
||||||
|
"filtered": 100,
|
||||||
|
"index_condition": "(t2.a1 < 5)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explain format=json select * from t2 where a1=1 or b1=2;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "index_merge",
|
||||||
|
"possible_keys": ["a1", "b1"],
|
||||||
|
"key_length": "5,5",
|
||||||
|
"index_merge": {
|
||||||
|
"sort_union": {
|
||||||
|
"range": {
|
||||||
|
"key": "a1",
|
||||||
|
"used_key_parts": ["a1"]
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"key": "b1",
|
||||||
|
"used_key_parts": ["b1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rows": 2,
|
||||||
|
"filtered": 100,
|
||||||
|
"attached_condition": "((t2.a1 = 1) or (t2.b1 = 2))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explain format=json select * from t2 where a1=1 or (b1=2 and b2=3);
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "index_merge",
|
||||||
|
"possible_keys": ["a1", "b1"],
|
||||||
|
"key_length": "5,10",
|
||||||
|
"index_merge": {
|
||||||
|
"sort_union": {
|
||||||
|
"range": {
|
||||||
|
"key": "a1",
|
||||||
|
"used_key_parts": ["a1"]
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"key": "b1",
|
||||||
|
"used_key_parts": ["b1", "b2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rows": 2,
|
||||||
|
"filtered": 100,
|
||||||
|
"attached_condition": "((t2.a1 = 1) or ((t2.b1 = 2) and (t2.b2 = 3)))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Try ref access on two key components
|
||||||
|
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
|
||||||
|
EXPLAIN
|
||||||
|
{
|
||||||
|
"query_block": {
|
||||||
|
"select_id": 1,
|
||||||
|
"table": {
|
||||||
|
"table_name": "t0",
|
||||||
|
"access_type": "ALL",
|
||||||
|
"rows": 10,
|
||||||
|
"filtered": 100,
|
||||||
|
"attached_condition": "(t0.a is not null)"
|
||||||
|
},
|
||||||
|
"table": {
|
||||||
|
"table_name": "t2",
|
||||||
|
"access_type": "ref",
|
||||||
|
"possible_keys": ["b1"],
|
||||||
|
"key": "b1",
|
||||||
|
"key_length": "10",
|
||||||
|
"used_key_parts": ["b1", "b2"],
|
||||||
|
"ref": ["test.t0.a", "const"],
|
||||||
|
"rows": 1,
|
||||||
|
"filtered": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop table t1;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
@ -14,14 +14,29 @@ explain format=json select * from t0 where 1>2;
|
|||||||
|
|
||||||
explain format=json select * from t0 where a<3;
|
explain format=json select * from t0 where a<3;
|
||||||
|
|
||||||
|
--echo # Try a basic join
|
||||||
create table t1 (a int, b int, filler char(32), key(a));
|
create table t1 (a int, b int, filler char(32), key(a));
|
||||||
insert into t1
|
insert into t1
|
||||||
select
|
select
|
||||||
A.a + B.a* 10 + C.a * 100,
|
a.a + b.a* 10 + c.a * 100,
|
||||||
A.a + B.a* 10 + C.a * 100,
|
a.a + b.a* 10 + c.a * 100,
|
||||||
'filler'
|
'filler'
|
||||||
from t0 A, t0 B, t0 C;
|
from t0 a, t0 b, t0 c;
|
||||||
|
|
||||||
explain format=json select * from t0,t1 where t1.a=t0.a;
|
explain format=json select * from t0,t1 where t1.a=t0.a;
|
||||||
|
|
||||||
|
--echo # Try range and index_merge
|
||||||
|
create table t2 (a1 int, a2 int, b1 int, b2 int, key(a1,a2), key(b1,b2));
|
||||||
|
insert into t2 select a,a,a,a from t1;
|
||||||
|
|
||||||
|
explain format=json select * from t2 where a1<5;
|
||||||
|
|
||||||
|
explain format=json select * from t2 where a1=1 or b1=2;
|
||||||
|
explain format=json select * from t2 where a1=1 or (b1=2 and b2=3);
|
||||||
|
|
||||||
|
--echo # Try ref access on two key components
|
||||||
|
|
||||||
|
explain format=json select * from t0,t2 where t2.b1=t0.a and t2.b2=4;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
drop table t0;
|
drop table t0;
|
||||||
|
@ -12105,7 +12105,7 @@ Explain_quick_select* QUICK_RANGE_SELECT::get_explain(MEM_ROOT *alloc)
|
|||||||
{
|
{
|
||||||
Explain_quick_select *res;
|
Explain_quick_select *res;
|
||||||
if ((res= new (alloc) Explain_quick_select(QS_TYPE_RANGE)))
|
if ((res= new (alloc) Explain_quick_select(QS_TYPE_RANGE)))
|
||||||
res->range.set(alloc, head->key_info[index].name, max_used_key_length);
|
res->range.set(alloc, &head->key_info[index], max_used_key_length);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12114,7 +12114,7 @@ Explain_quick_select* QUICK_GROUP_MIN_MAX_SELECT::get_explain(MEM_ROOT *alloc)
|
|||||||
{
|
{
|
||||||
Explain_quick_select *res;
|
Explain_quick_select *res;
|
||||||
if ((res= new (alloc) Explain_quick_select(QS_TYPE_GROUP_MIN_MAX)))
|
if ((res= new (alloc) Explain_quick_select(QS_TYPE_GROUP_MIN_MAX)))
|
||||||
res->range.set(alloc, head->key_info[index].name, max_used_key_length);
|
res->range.set(alloc, &head->key_info[index], max_used_key_length);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,7 +541,7 @@ void Explain_table_access::push_extra(enum explain_extra_tag extra_tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Explain_table_access::fill_key_str(String *key_str)
|
void Explain_table_access::fill_key_str(String *key_str, bool is_json)
|
||||||
{
|
{
|
||||||
const CHARSET_INFO *cs= system_charset_info;
|
const CHARSET_INFO *cs= system_charset_info;
|
||||||
bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
|
bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
|
||||||
@ -562,6 +562,9 @@ void Explain_table_access::fill_key_str(String *key_str)
|
|||||||
if (quick_info)
|
if (quick_info)
|
||||||
{
|
{
|
||||||
StringBuffer<64> buf2;
|
StringBuffer<64> buf2;
|
||||||
|
if (is_json)
|
||||||
|
quick_info->print_extra_recursive(&buf2);
|
||||||
|
else
|
||||||
quick_info->print_key(&buf2);
|
quick_info->print_key(&buf2);
|
||||||
key_str->append(buf2);
|
key_str->append(buf2);
|
||||||
}
|
}
|
||||||
@ -570,6 +573,16 @@ void Explain_table_access::fill_key_str(String *key_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill "key_length".
|
||||||
|
- this is just used key length for ref/range
|
||||||
|
- for index_merge, it is a comma-separated list of lengths.
|
||||||
|
- for hash join, it is key_len:pseudo_key_len
|
||||||
|
|
||||||
|
The column looks identical in tabular and json forms. In JSON, we consider
|
||||||
|
the column legacy, it is superceded by used_key_parts.
|
||||||
|
*/
|
||||||
|
|
||||||
void Explain_table_access::fill_key_len_str(String *key_len_str)
|
void Explain_table_access::fill_key_len_str(String *key_len_str)
|
||||||
{
|
{
|
||||||
bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
|
bool is_hj= (type == JT_HASH || type == JT_HASH_NEXT ||
|
||||||
@ -601,6 +614,35 @@ void Explain_table_access::fill_key_len_str(String *key_len_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Explain_index_use::set(MEM_ROOT *mem_root, KEY *key, uint key_len_arg)
|
||||||
|
{
|
||||||
|
set_pseudo_key(mem_root, key->name);
|
||||||
|
key_len= key_len_arg;
|
||||||
|
uint len= 0;
|
||||||
|
for (uint i= 0; i < key->usable_key_parts; i++)
|
||||||
|
{
|
||||||
|
key_parts_list.append_str(mem_root, key->key_part[i].field->field_name);
|
||||||
|
len += key->key_part[i].store_length;
|
||||||
|
if (len >= key_len_arg)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Explain_index_use::set_pseudo_key(MEM_ROOT *root, const char* key_name_arg)
|
||||||
|
{
|
||||||
|
if (key_name_arg)
|
||||||
|
{
|
||||||
|
size_t name_len= strlen(key_name_arg);
|
||||||
|
if ((key_name= (char*)alloc_root(root, name_len+1)))
|
||||||
|
memcpy(key_name, key_name_arg, name_len+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
key_name= NULL;
|
||||||
|
key_len= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double Explain_table_access::get_r_filtered()
|
double Explain_table_access::get_r_filtered()
|
||||||
{
|
{
|
||||||
//psergey-todo: modify this to produce separate filtered% for both parts of
|
//psergey-todo: modify this to produce separate filtered% for both parts of
|
||||||
@ -660,7 +702,7 @@ int Explain_table_access::print_explain(select_result_sink *output, uint8 explai
|
|||||||
|
|
||||||
/* `key` */
|
/* `key` */
|
||||||
StringBuffer<64> key_str;
|
StringBuffer<64> key_str;
|
||||||
fill_key_str(&key_str);
|
fill_key_str(&key_str, false);
|
||||||
|
|
||||||
if (key_str.length() > 0)
|
if (key_str.length() > 0)
|
||||||
push_string(&item_list, &key_str);
|
push_string(&item_list, &key_str);
|
||||||
@ -861,15 +903,16 @@ void Explain_table_access::print_explain_json(Json_writer *writer,
|
|||||||
writer->add_str(name);
|
writer->add_str(name);
|
||||||
writer->end_array();
|
writer->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `key` */
|
/* `key` */
|
||||||
|
/* For non-basic quick select, 'key' will not be present */
|
||||||
|
if (!quick_info || quick_info->is_basic())
|
||||||
|
{
|
||||||
StringBuffer<64> key_str;
|
StringBuffer<64> key_str;
|
||||||
fill_key_str(&key_str);
|
fill_key_str(&key_str, true);
|
||||||
if (key_str.length())
|
if (key_str.length())
|
||||||
writer->add_member("key").add_str(key_str);
|
writer->add_member("key").add_str(key_str);
|
||||||
|
}
|
||||||
/* `used_key_parts` */
|
|
||||||
if (key_str.length())
|
|
||||||
writer->add_member("used_key_parts").add_str("TODO");
|
|
||||||
|
|
||||||
/* `key_length` */
|
/* `key_length` */
|
||||||
StringBuffer<64> key_len_str;
|
StringBuffer<64> key_len_str;
|
||||||
@ -877,8 +920,34 @@ void Explain_table_access::print_explain_json(Json_writer *writer,
|
|||||||
if (key_len_str.length())
|
if (key_len_str.length())
|
||||||
writer->add_member("key_length").add_str(key_len_str);
|
writer->add_member("key_length").add_str(key_len_str);
|
||||||
|
|
||||||
|
/* `used_key_parts` */
|
||||||
|
String_list *parts_list= NULL;
|
||||||
|
if (quick_info && quick_info->is_basic())
|
||||||
|
parts_list= &quick_info->range.key_parts_list;
|
||||||
|
else
|
||||||
|
parts_list= &key.key_parts_list;
|
||||||
|
|
||||||
|
if (parts_list && !parts_list->is_empty())
|
||||||
|
{
|
||||||
|
List_iterator_fast<char> it(*parts_list);
|
||||||
|
const char *name;
|
||||||
|
writer->add_member("used_key_parts").start_array();
|
||||||
|
while ((name= it++))
|
||||||
|
writer->add_str(name);
|
||||||
|
writer->end_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quick_info && !quick_info->is_basic())
|
||||||
|
{
|
||||||
|
writer->add_member("index_merge").start_object();
|
||||||
|
quick_info->print_json(writer);
|
||||||
|
writer->end_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: here, if quick select is not basic, print its nested form.
|
||||||
|
|
||||||
/* `ref` */
|
/* `ref` */
|
||||||
// TODO: need to print this as an array.
|
|
||||||
if (!ref_list.is_empty())
|
if (!ref_list.is_empty())
|
||||||
{
|
{
|
||||||
List_iterator_fast<char> it(ref_list);
|
List_iterator_fast<char> it(ref_list);
|
||||||
@ -1046,6 +1115,35 @@ void Explain_quick_select::print_extra(String *str)
|
|||||||
print_extra_recursive(str);
|
print_extra_recursive(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Explain_quick_select::print_json(Json_writer *writer)
|
||||||
|
{
|
||||||
|
if (is_basic())
|
||||||
|
{
|
||||||
|
writer->add_member("range").start_object();
|
||||||
|
|
||||||
|
writer->add_member("key").add_str(range.get_key_name());
|
||||||
|
|
||||||
|
List_iterator_fast<char> it(range.key_parts_list);
|
||||||
|
const char *name;
|
||||||
|
writer->add_member("used_key_parts").start_array();
|
||||||
|
while ((name= it++))
|
||||||
|
writer->add_str(name);
|
||||||
|
writer->end_array();
|
||||||
|
|
||||||
|
writer->end_object();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer->add_member(get_name_by_type()).start_object();
|
||||||
|
|
||||||
|
List_iterator_fast<Explain_quick_select> it (children);
|
||||||
|
Explain_quick_select* child;
|
||||||
|
while ((child = it++))
|
||||||
|
child->print_json(writer);
|
||||||
|
|
||||||
|
writer->end_object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Explain_quick_select::print_extra_recursive(String *str)
|
void Explain_quick_select::print_extra_recursive(String *str)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,15 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
|
||||||
|
class String_list: public List<char>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool append_str(MEM_ROOT *mem_root, const char *str);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Data structures for ANALYZE */
|
/* Data structures for ANALYZE */
|
||||||
class Table_access_tracker
|
class Table_access_tracker
|
||||||
{
|
{
|
||||||
@ -417,21 +426,16 @@ class Explain_index_use : public Sql_alloc
|
|||||||
{
|
{
|
||||||
char *key_name;
|
char *key_name;
|
||||||
uint key_len;
|
uint key_len;
|
||||||
/* will add #keyparts here if we implement EXPLAIN FORMAT=JSON */
|
|
||||||
public:
|
public:
|
||||||
|
String_list key_parts_list;
|
||||||
|
|
||||||
void set(MEM_ROOT *root, const char *key_name_arg, uint key_len_arg)
|
void clear()
|
||||||
{
|
{
|
||||||
if (key_name_arg)
|
|
||||||
{
|
|
||||||
size_t name_len= strlen(key_name_arg);
|
|
||||||
if ((key_name= (char*)alloc_root(root, name_len+1)))
|
|
||||||
memcpy(key_name, key_name_arg, name_len+1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
key_name= NULL;
|
key_name= NULL;
|
||||||
key_len= key_len_arg;
|
key_len= (uint)-1;
|
||||||
}
|
}
|
||||||
|
void set(MEM_ROOT *root, KEY *key_name, uint key_len_arg);
|
||||||
|
void set_pseudo_key(MEM_ROOT *root, const char *key_name);
|
||||||
|
|
||||||
inline const char *get_key_name() { return key_name; }
|
inline const char *get_key_name() { return key_name; }
|
||||||
inline uint get_key_len() { return key_len; }
|
inline uint get_key_len() { return key_len; }
|
||||||
@ -449,6 +453,13 @@ public:
|
|||||||
|
|
||||||
const int quick_type;
|
const int quick_type;
|
||||||
|
|
||||||
|
bool is_basic()
|
||||||
|
{
|
||||||
|
return (quick_type == QUICK_SELECT_I::QS_TYPE_RANGE ||
|
||||||
|
quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC ||
|
||||||
|
quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
|
/* This is used when quick_type == QUICK_SELECT_I::QS_TYPE_RANGE */
|
||||||
Explain_index_use range;
|
Explain_index_use range;
|
||||||
|
|
||||||
@ -458,19 +469,15 @@ public:
|
|||||||
void print_extra(String *str);
|
void print_extra(String *str);
|
||||||
void print_key(String *str);
|
void print_key(String *str);
|
||||||
void print_key_len(String *str);
|
void print_key_len(String *str);
|
||||||
private:
|
|
||||||
|
void print_json(Json_writer *writer);
|
||||||
|
|
||||||
void print_extra_recursive(String *str);
|
void print_extra_recursive(String *str);
|
||||||
|
private:
|
||||||
const char *get_name_by_type();
|
const char *get_name_by_type();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class String_list: public List<char>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool append_str(MEM_ROOT *mem_root, const char *str);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
EXPLAIN data structure for a single JOIN_TAB.
|
EXPLAIN data structure for a single JOIN_TAB.
|
||||||
*/
|
*/
|
||||||
@ -565,7 +572,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void append_tag_name(String *str, enum explain_extra_tag tag);
|
void append_tag_name(String *str, enum explain_extra_tag tag);
|
||||||
void fill_key_str(String *key_str);
|
void fill_key_str(String *key_str, bool is_json);
|
||||||
void fill_key_len_str(String *key_len_str);
|
void fill_key_len_str(String *key_len_str);
|
||||||
double get_r_filtered();
|
double get_r_filtered();
|
||||||
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
|
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
|
||||||
|
@ -23310,7 +23310,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
quick_type= -1;
|
quick_type= -1;
|
||||||
QUICK_SELECT_I *quick= NULL;
|
QUICK_SELECT_I *quick= NULL;
|
||||||
|
|
||||||
eta->key.set(thd->mem_root, NULL, (uint)-1);
|
eta->key.clear();
|
||||||
eta->quick_info= NULL;
|
eta->quick_info= NULL;
|
||||||
|
|
||||||
tab->tracker= &eta->tracker;
|
tab->tracker= &eta->tracker;
|
||||||
@ -23437,7 +23437,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
|
|
||||||
if (key_info) /* 'index' or 'ref' access */
|
if (key_info) /* 'index' or 'ref' access */
|
||||||
{
|
{
|
||||||
eta->key.set(thd->mem_root, key_info->name, key_len);
|
eta->key.set(thd->mem_root, key_info, key_len);
|
||||||
|
|
||||||
if (tab->ref.key_parts && tab_type != JT_FT)
|
if (tab->ref.key_parts && tab_type != JT_FT)
|
||||||
{
|
{
|
||||||
@ -23458,8 +23458,10 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
|
if (tab_type == JT_HASH_NEXT) /* full index scan + hash join */
|
||||||
{
|
{
|
||||||
eta->hash_next_key.set(thd->mem_root,
|
eta->hash_next_key.set(thd->mem_root,
|
||||||
table->key_info[tab->index].name,
|
& table->key_info[tab->index],
|
||||||
table->key_info[tab->index].key_length);
|
table->key_info[tab->index].key_length);
|
||||||
|
// psergey-todo: ^ is the above correct? are we necessarily joining on all
|
||||||
|
// columns?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key_info)
|
if (!key_info)
|
||||||
@ -23490,7 +23492,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta, table_map prefix_tab
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key_name_buf.length())
|
if (key_name_buf.length())
|
||||||
eta->key.set(thd->mem_root, key_name_buf.c_ptr_safe(), -1);
|
eta->key.set_pseudo_key(thd->mem_root, key_name_buf.c_ptr_safe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user