MDEV-18880: Optimizer trace prints date in hexadecimal

Introduced a print_key_value function to makes sure that the trace prints data in readable format
for readable characters and the rest of the characters are printed as hexadecimal.
This commit is contained in:
Varun 2019-06-10 15:56:36 +05:30
parent 40ff8019d2
commit a0cb7551a4
9 changed files with 501 additions and 31 deletions

View File

@ -1446,7 +1446,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
{
"index": "id",
"covering": true,
"ranges": ["(0x24a20f) <= (a)"],
"ranges": ["(2001-01-04) <= (a)"],
"rows": 9,
"cost": 2.35
}
@ -1462,7 +1462,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"rows": 9,
"cost": 2.35,
"key_parts_used_for_access": ["id"],
"ranges": ["(0x24a20f) <= (a)"],
"ranges": ["(2001-01-04) <= (a)"],
"chosen": false,
"cause": "cost"
},
@ -1624,7 +1624,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
{
"index": "id",
"covering": true,
"ranges": ["(0x24a20f) <= (a) <= (0x24a20f)"],
"ranges": ["(2001-01-04) <= (a) <= (2001-01-04)"],
"rows": 9,
"cost": 2.35
}
@ -1640,7 +1640,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"rows": 9,
"cost": 2.35,
"key_parts_used_for_access": ["id", "a"],
"ranges": ["(0x24a20f) <= (a) <= (0x24a20f)"],
"ranges": ["(2001-01-04) <= (a) <= (2001-01-04)"],
"chosen": false,
"cause": "cost"
},
@ -6130,7 +6130,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
"index": "start_date",
"ranges":
[
"(0x4ac60f,NULL) < (start_date,end_date)"
"(2019-02-10,NULL) < (start_date,end_date)"
],
"rowid_ordered": false,
"using_mrr": false,
@ -6214,7 +6214,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
"index": "i_b",
"ranges":
[
"(0xd95b94336a9946a39cf5b58cfe772d8c) <= (b) <= (0xd95b94336a9946a39cf5b58cfe772d8c)"
"(\xD9[\x943j\x99F\xA3\x9C\xF5\xB5\x8C\xFEw-\x8C) <= (b) <= (\xD9[\x943j\x99F\xA3\x9C\xF5\xB5\x8C\xFEw-\x8C)"
],
"rowid_ordered": true,
"using_mrr": false,
@ -6268,4 +6268,290 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
}
]
drop table t1;
#
# MDEV-18880: Optimizer trace prints date in hexadecimal
#
CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10) CHARSET BINARY , INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 13 const 1 Using index condition
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\x0A) <= (b) <= (ab\x0A)"
],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.3787,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
ALTER TABLE t1 modify column b BINARY(10) AFTER i;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 11 const 1 Using index condition
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\x0A\x00\x00\x00\x00\x00\x00\x00) <= (b) <= (ab\x0A\x00\x00\x00\x00\x00\x00\x00)"
],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.3785,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
ALTER TABLE t1 modify column b VARBINARY(10) AFTER i;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 13 const 1 Using index condition
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\x0A) <= (b) <= (ab\x0A)"
],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.3787,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b CHAR(10), INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 11 const 1 Using index condition
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\n) <= (b) <= (ab\n)"
],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 2.3785,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b blob , INDEX i_b(b));
Warnings:
Note 1071 Specified key was too long; max key length is 1000 bytes
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b= 'ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 1003 const 1 Using where
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\x0A) <= (b) <= (ab\x0A)"
],
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 1,
"cost": 3.5719,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10), INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, 'ab\n');
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref i_b i_b 13 const 2 Using index condition
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "i_b",
"ranges":
[
"(ab\n) <= (b) <= (ab\n)"
],
"rowid_ordered": true,
"using_mrr": false,
"index_only": false,
"rows": 2,
"cost": 3.6324,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1;
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table one_k (a int);
insert into one_k select A.a + B.a*10 + C.a*100 from t0 A, t0 B, t0 C;
create table t1 (start_date date, end_date date, filler char(100), key(start_date, end_date)) ;
insert into t1 select date_add(now(), interval a day), date_add(now(), interval (a+7) day), 'data' from one_k;
explain format=json select * from t1 force index(start_date) where start_date >= '2019-02-10' and end_date <'2019-04-01';
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["start_date"],
"key": "start_date",
"key_length": "8",
"used_key_parts": ["start_date", "end_date"],
"rows": 1000,
"filtered": 100,
"index_condition": "t1.start_date >= '2019-02-10' and t1.end_date < '2019-04-01'"
}
}
}
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "start_date",
"ranges":
[
"(2019-02-10,NULL) < (start_date,end_date)"
],
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 1000,
"cost": 1282.2,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1, t0, one_k;
set optimizer_trace='enabled=off';

View File

@ -444,4 +444,58 @@ select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) fr
drop table t1;
--echo #
--echo # MDEV-18880: Optimizer trace prints date in hexadecimal
--echo #
CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10) CHARSET BINARY , INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
ALTER TABLE t1 modify column b BINARY(10) AFTER i;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
ALTER TABLE t1 modify column b VARBINARY(10) AFTER i;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b CHAR(10), INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b blob , INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, NULL);
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b= 'ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10), INDEX i_b(b));
INSERT INTO t1 VALUES (1, 'ab\n');
INSERT INTO t1 VALUES (2, 'ab\n');
set optimizer_trace=1;
EXPLAIN SELECT * FROM t1 WHERE b='ab\n';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table one_k (a int);
insert into one_k select A.a + B.a*10 + C.a*100 from t0 A, t0 B, t0 C;
create table t1 (start_date date, end_date date, filler char(100), key(start_date, end_date)) ;
--disable_warnings
insert into t1 select date_add(now(), interval a day), date_add(now(), interval (a+7) day), 'data' from one_k;
--enable_warnings
explain format=json select * from t1 force index(start_date) where start_date >= '2019-02-10' and end_date <'2019-04-01';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1, t0, one_k;
set optimizer_trace='enabled=off';

View File

@ -0,0 +1,54 @@
create or replace table t1 (col1 char(10) character set ucs2, filler char(100), key(col1)) ;
insert into t1 values ('a', 'a');
insert into t1 values ('a', 'a');
set optimizer_trace=1;
explain format=json select * from t1 force index(col1) where col1 >='a';
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t1",
"access_type": "range",
"possible_keys": ["col1"],
"key": "col1",
"key_length": "21",
"used_key_parts": ["col1"],
"rows": 2,
"filtered": 100,
"index_condition": "t1.col1 >= 'a'"
}
}
}
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
[
{
"range_scan_alternatives":
[
{
"index": "col1",
"ranges":
[
"(a) <= (col1)"
],
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 2,
"cost": 3.7609,
"chosen": true
}
],
"analyzing_roworder_intersect":
{
"cause": "too few roworder scans"
},
"analyzing_index_merge_union":
[
]
}
]
drop table t1;

View File

@ -0,0 +1,10 @@
--source include/not_embedded.inc
--source include/have_ucs2.inc
create or replace table t1 (col1 char(10) character set ucs2, filler char(100), key(col1)) ;
insert into t1 values ('a', 'a');
insert into t1 values ('a', 'a');
set optimizer_trace=1;
explain format=json select * from t1 force index(col1) where col1 >='a';
select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
drop table t1;

View File

@ -11242,3 +11242,58 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
thd->variables.sql_mode= sql_mode_backup;
return rc;
}
void Field::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
print_key_value_binary(out, ptr, length);
else
val_str(out);
}
void Field_string::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
{
size_t len= field_charset->cset->lengthsp(field_charset, (const char*) ptr, length);
print_key_value_binary(out, ptr, static_cast<uint32>(len));
}
else
{
THD *thd= get_thd();
sql_mode_t sql_mode_backup= thd->variables.sql_mode;
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
val_str(out,out);
thd->variables.sql_mode= sql_mode_backup;
}
}
void Field_varstring::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
print_key_value_binary(out, get_data(), get_length());
else
val_str(out,out);
}
void Field_blob::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
{
uchar *blob;
memcpy(&blob, ptr+packlength, sizeof(uchar*));
print_key_value_binary(out, blob, get_length());
}
else
val_str(out, out);
}
void Field::print_key_value_binary(String *out, const uchar* key, uint32 length)
{
out->append_semi_hex((const char*)key, length, charset());
}

View File

@ -1383,6 +1383,8 @@ public:
virtual int set_time() { return 1; }
bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
int cuted_increment, ulong current_row=0) const;
virtual void print_key_value(String *out, uint32 length);
void print_key_value_binary(String *out, const uchar* key, uint32 length);
protected:
bool set_warning(unsigned int code, int cuted_increment) const
{
@ -3592,6 +3594,7 @@ public:
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
virtual uint get_key_image(uchar *buff,uint length, imagetype type);
void print_key_value(String *out, uint32 length);
private:
int save_field_metadata(uchar *first_byte);
};
@ -3697,6 +3700,7 @@ public:
uint is_equal(Create_field *new_field);
void hash(ulong *nr, ulong *nr2);
uint length_size() { return length_bytes; }
void print_key_value(String *out, uint32 length);
private:
int save_field_metadata(uchar *first_byte);
};
@ -4035,6 +4039,7 @@ public:
uint32 char_length() const;
uint32 character_octet_length() const;
uint is_equal(Create_field *new_field);
void print_key_value(String *out, uint32 length);
friend void TABLE::remember_blob_values(String *blob_storage);
friend void TABLE::restore_blob_values(String *blob_storage);
@ -4159,6 +4164,10 @@ public:
geometry_type get_geometry_type() { return geom_type; };
static geometry_type geometry_type_merge(geometry_type, geometry_type);
uint get_srid() { return srid; }
void print_key_value(String *out, uint32 length)
{
out->append(STRING_WITH_LEN("unprintable_geometry_value"));
}
};
uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields);
@ -4466,6 +4475,11 @@ public:
{
return get_mm_leaf_int(param, key_part, cond, op, value, true);
}
void print_key_value(String *out, uint32 length)
{
val_int_as_str(out, 1);
}
private:
virtual size_t do_last_null_byte() const;
int save_field_metadata(uchar *first_byte);

View File

@ -15835,12 +15835,10 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
{
// Byte 0 of a nullable key is the null-byte. If set, key is NULL.
if (field->real_maybe_null() && *key)
{
out->append(STRING_WITH_LEN("NULL"));
else
(field->type() == MYSQL_TYPE_GEOMETRY)
? out->append(STRING_WITH_LEN("unprintable_geometry_value"))
: out->append(STRING_WITH_LEN("unprintable_blob_value"));
goto next;
goto next;
}
}
if (field->real_maybe_null())
@ -15859,28 +15857,12 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
store_length--;
}
/*
Binary data cannot be converted to UTF8 which is what the
optimizer trace expects. If the column is binary, the hex
representation is printed to the trace instead.
*/
if (field->flags & BINARY_FLAG)
{
out->append("0x");
for (uint i = 0; i < store_length; i++)
{
out->append(_dig_vec_lower[*(key + i) >> 4]);
out->append(_dig_vec_lower[*(key + i) & 0x0F]);
}
goto next;
}
field->set_key_image(key, key_part->length);
if (field->type() == MYSQL_TYPE_BIT)
(void)field->val_int_as_str(&tmp, 1); // may change tmp's charset
field->print_key_value(&tmp, key_part->length);
if (field->charset() == &my_charset_bin)
out->append(tmp.ptr(), tmp.length(), tmp.charset());
else
field->val_str(&tmp); // may change tmp's charset
out->append(tmp.ptr(), tmp.length(), tmp.charset());
tmp.print(out, system_charset_info);
next:
if (key + store_length < key_end)

View File

@ -1196,3 +1196,15 @@ uint convert_to_printable(char *to, size_t to_len,
*t= '\0';
return (uint) (t - to);
}
bool String::append_semi_hex(const char *s, uint len, CHARSET_INFO *cs)
{
size_t dst_len= len * 4 + 1; //extra length for the '\0' character
if (reserve(dst_len))
return true;
uint nbytes= convert_to_printable(Ptr + str_length, dst_len, s, len, cs);
DBUG_ASSERT((ulonglong) str_length + nbytes < UINT_MAX32);
str_length+= nbytes;
return false;
}

View File

@ -674,6 +674,7 @@ public:
int reserve(size_t space_needed)
{
DBUG_ASSERT((ulonglong) str_length + space_needed < UINT_MAX32);
return realloc(str_length + space_needed);
}
int reserve(size_t space_needed, size_t grow_by);
@ -959,6 +960,8 @@ public:
{
return !sortcmp(this, other, cs);
}
private:
bool append_semi_hex(const char *s, uint len, CHARSET_INFO *cs);
};