revision-id: ee6c668f24c4e9e49b742b8a2bcaac4ac2298ac0 (mariadb-10.5.0-275-gee6c668f24c) parent(s): 0c35e80dc9ff24bcb8e710cb8cb16428c8c9986f author: Sergei Petrunia committer: Sergei Petrunia timestamp: 2020-03-09 00:29:48 +0300 message: MDEV-21784: Performance testing for packed sort keys A piece of cumulative patch for MDEV-21580 Allow packed sort keys in sort buffer which just adds some virtual functions (without any calls to them) --- plugin/type_inet/sql_type_inet.cc | 23 ++++ plugin/type_inet/sql_type_inet.h | 3 + sql/field.cc | 61 ++++++++++ sql/field.h | 27 ++++- sql/filesort.cc | 231 ++++++++++++++++++++++++++++++++++++++ sql/sql_class.h | 5 + sql/sql_type.h | 45 ++++++++ 7 files changed, 394 insertions(+), 1 deletion(-) diff --git a/plugin/type_inet/sql_type_inet.cc b/plugin/type_inet/sql_type_inet.cc index 6803bdba434..a660df053a8 100644 --- a/plugin/type_inet/sql_type_inet.cc +++ b/plugin/type_inet/sql_type_inet.cc @@ -1377,6 +1377,29 @@ void Type_handler_inet6::make_sort_key(uchar *to, Item *item, memcpy(to, tmp.ptr(), tmp.length()); } +uint +Type_handler_inet6::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + DBUG_ASSERT(item->type_handler() == this); + NativeBufferInet6 tmp; + item->val_native_result(current_thd, &tmp); + if (item->maybe_null) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + DBUG_ASSERT(!item->null_value); + DBUG_ASSERT(Inet6::binary_length() == tmp.length()); + DBUG_ASSERT(Inet6::binary_length() == sort_field->length); + memcpy(to, tmp.ptr(), tmp.length()); + return tmp.length(); +} void Type_handler_inet6::sortlength(THD *thd, const Type_std_attributes *item, diff --git a/plugin/type_inet/sql_type_inet.h b/plugin/type_inet/sql_type_inet.h index b483ff94e8d..dd4f530dcf8 100644 --- a/plugin/type_inet/sql_type_inet.h +++ b/plugin/type_inet/sql_type_inet.h @@ -516,6 +516,9 @@ class Type_handler_inet6: public Type_handler void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; diff --git a/sql/field.cc b/sql/field.cc index 1ce49b0bdfa..62dafd55b57 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1029,6 +1029,61 @@ void Field::make_sort_key(uchar *buff,uint length) } +/* + @brief + Create a packed sort key + + @param buff buffer where values are written + @param sort_field sort column structure + + @retval + length of the bytes written, does not include the NULL bytes +*/ +uint +Field::make_packed_sort_key(uchar *buff, const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + sort_string(buff, sort_field->original_length); + return sort_field->original_length; +} + + +uint +Field_longstr::make_packed_sort_key(uchar *buff, + const SORT_FIELD_ATTR *sort_field) +{ + if (maybe_null()) + { + if (is_null()) + { + *buff++= 0; + return 0; // For NULL values don't write any data + } + *buff++=1; + } + uchar *end= pack_sort_string(buff, sort_field); + return static_cast<int>(end-buff); +} + + +uchar* +Field_longstr::pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field) +{ + String buf; + val_str(&buf, &buf); + return to + sort_field->pack_sort_string(to, buf.lex_cstring(), + field_charset()); +} + + /** @brief Determine the relative position of the field value in a numeric interval @@ -8531,6 +8586,12 @@ uint32 Field_blob::sort_length() const } +uint32 Field_blob::sort_suffix_length() const +{ + return field_charset() == &my_charset_bin ? packlength : 0; +} + + void Field_blob::sort_string(uchar *to,uint length) { String buf; diff --git a/sql/field.h b/sql/field.h index 4a8eec35b05..47abae87c1f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -33,6 +33,7 @@ #include "compat56.h" #include "sql_type.h" /* Type_std_attributes */ #include "field_comp.h" +#include "filesort.h" class Send_field; class Copy_field; @@ -1075,6 +1076,12 @@ class Field: public Value_source virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } + /* + sort_suffix_length() return the length bytes needed to store the length + for binary charset + */ + virtual uint32 sort_suffix_length() const { return 0; } + /* Get the number bytes occupied by the value in the field. CHAR values are stripped of trailing spaces. @@ -1410,7 +1417,17 @@ class Field: public Value_source return bytes; } + /* + Create mem-comparable sort keys + */ void make_sort_key(uchar *buff, uint length); + + /* + create a compact sort key which can be compared with a comparison + function. They are called packed sort keys + */ + virtual uint make_packed_sort_key(uchar *buff, + const SORT_FIELD_ATTR *sort_field); virtual void make_send_field(Send_field *); virtual void sort_string(uchar *buff,uint length)=0; virtual bool optimize_range(uint idx, uint part) const; @@ -2140,7 +2157,10 @@ class Field_longstr :public Field_str bool can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const; - bool is_packable() { return true; } + bool is_packable() override { return true; } + uint make_packed_sort_key(uchar *buff, + const SORT_FIELD_ATTR *sort_field)override; + uchar* pack_sort_string(uchar *to, const SORT_FIELD_ATTR *sort_field); }; /* base class for float and double and decimal (old one) */ @@ -4045,6 +4065,10 @@ class Field_varstring :public Field_longstr { return (uint32) field_length + (field_charset() == &my_charset_bin ? length_bytes : 0); } + virtual uint32 sort_suffix_length() const override + { + return (field_charset() == &my_charset_bin ? length_bytes : 0); + } Copy_func *get_copy_func(const Field *from) const override; bool memcpy_field_possible(const Field *from) const override; void update_data_type_statistics(Data_type_statistics *st) const override @@ -4353,6 +4377,7 @@ class Field_blob :public Field_longstr { { return (uint32) (packlength); } uint row_pack_length() const override { return pack_length_no_ptr(); } uint32 sort_length() const override; + uint32 sort_suffix_length() const override; uint32 value_length() override { return get_length(); } virtual uint32 max_data_length() const override { diff --git a/sql/filesort.cc b/sql/filesort.cc index 34fecd516b4..71556a17cc6 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1176,6 +1176,24 @@ Type_handler_timestamp_common::make_sort_key(uchar *to, Item *item, } +void +Type_handler::store_sort_key_longlong(uchar *to, bool unsigned_flag, + longlong value) const +{ + to[7]= (uchar) value; + to[6]= (uchar) (value >> 8); + to[5]= (uchar) (value >> 16); + to[4]= (uchar) (value >> 24); + to[3]= (uchar) (value >> 32); + to[2]= (uchar) (value >> 40); + to[1]= (uchar) (value >> 48); + if (unsigned_flag) /* Fix sign */ + to[0]= (uchar) (value >> 56); + else + to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */ +} + + void Type_handler::make_sort_key_longlong(uchar *to, bool maybe_null, @@ -1207,6 +1225,25 @@ Type_handler::make_sort_key_longlong(uchar *to, } +uint +Type_handler::make_packed_sort_key_longlong(uchar *to, bool maybe_null, + bool null_value, bool unsigned_flag, + longlong value, + const SORT_FIELD_ATTR *sort_field) const +{ + if (maybe_null) + { + if (null_value) + { + *to++= 0; + return 0; + } + *to++= 1; + } + store_sort_key_longlong(to, unsigned_flag, value); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; +} void Type_handler_decimal_result::make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, @@ -2375,3 +2412,197 @@ SORT_INFO::~SORT_INFO() free_data(); DBUG_VOID_RETURN; } + +/* + TODO varun: add comments here +*/ +uint +SORT_FIELD_ATTR::pack_sort_string(uchar *to, const LEX_CSTRING &str, + CHARSET_INFO *cs) const +{ + DBUG_ASSERT(0); + return 0; +/* + uchar *orig_to= to; + size_t length, data_length; + length= str.length; + + if (length + suffix_length <= original_length) + data_length= length; + else + data_length= original_length - suffix_length; + + // length stored in lowendian form + store_lowendian(data_length + suffix_length, to, length_bytes); + to+= length_bytes; + // copying data length bytes to the buffer + memcpy(to, (uchar*)str.str, data_length); + to+= data_length; + + if (cs == &my_charset_bin && suffix_length) + { + // suffix length stored in bigendian form + store_bigendian(str.length, to, suffix_length); + to+= suffix_length; + } + return static_cast<uint>(to - orig_to);*/ +} +uint +Type_handler_string_result::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + CHARSET_INFO *cs= item->collation.collation; + bool maybe_null= item->maybe_null; + + if (maybe_null) + *to++= 1; + + String tmp(param->tmp_buffer, param->sort_length, cs); + String *res= item->str_result(&tmp); + if (!res) + { + if (maybe_null) + { + *(to-1)= 0; + return 0; + } + else + { + /* purecov: begin deadcode */ + /* + This should only happen during extreme conditions if we run out + of memory or have an item marked not null when it can be null. + This code is here mainly to avoid a hard crash in this case. + */ + DBUG_ASSERT(0); + DBUG_PRINT("warning", + ("Got null on something that shouldn't be null")); + memset(to, 0, sort_field->length); // Avoid crash + /* purecov: end */ + return sort_field->original_length; + } + } + return sort_field->pack_sort_string(to, res->lex_cstring(), cs); +} + + +uint +Type_handler_int_result::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + longlong value= item->val_int_result(); + return make_packed_sort_key_longlong(to, item->maybe_null, + item->null_value, item->unsigned_flag, + value, sort_field); +} + + +uint +Type_handler_decimal_result::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf); + if (item->maybe_null) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0), + item->decimals); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; +} + + +uint +Type_handler_real_result::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + double value= item->val_result(); + if (item->maybe_null) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + change_double_for_sort(value, to); + DBUG_ASSERT(sort_field->original_length == sort_field->length); + return sort_field->original_length; +} + + +uint +Type_handler_temporal_result::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + MYSQL_TIME buf; + // This is a temporal type. No nanoseconds. Rounding mode is not important. + DBUG_ASSERT(item->cmp_type() == TIME_RESULT); + static const Temporal::Options opt(TIME_INVALID_DATES, TIME_FRAC_NONE); + if (item->get_date_result(current_thd, &buf, opt)) + { + DBUG_ASSERT(item->maybe_null); + DBUG_ASSERT(item->null_value); + return make_packed_sort_key_longlong(to, item->maybe_null, true, + item->unsigned_flag, 0, sort_field); + } + return make_packed_sort_key_longlong(to, item->maybe_null, false, + item->unsigned_flag, pack_time(&buf), + sort_field); +} + + +uint +Type_handler_timestamp_common::make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const +{ + THD *thd= current_thd; + uint binlen= my_timestamp_binary_length(item->decimals); + Timestamp_or_zero_datetime_native_null native(thd, item); + if (native.is_null() || native.is_zero_datetime()) + { + // NULL or '0000-00-00 00:00:00' + if (item->maybe_null) + { + *to++=0; + return 0; + } + else + { + bzero(to, binlen); + return binlen; + } + } + else + { + if (item->maybe_null) + *to++= 1; + if (native.length() != binlen) + { + /* + Some items can return native representation with a different + number of fractional digits, e.g.: GREATEST(ts_3, ts_4) can + return a value with 3 fractional digits, although its fractional + precision is 4. Re-pack with a proper precision now. + */ + Timestamp(native).to_native(&native, item->datetime_precision(thd)); + } + DBUG_ASSERT(native.length() == binlen); + memcpy((char *) to, native.ptr(), binlen); + return binlen; + } +} + diff --git a/sql/sql_class.h b/sql/sql_class.h index 13b2659789d..fce35bff2f5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6255,6 +6255,11 @@ struct SORT_FIELD_ATTR { uint length; /* Length of sort field */ uint suffix_length; /* Length suffix (0-4) */ + /* Max. length of the original value, in bytes */ + uint original_length; + + uint pack_sort_string(uchar *to, const LEX_CSTRING &str, + CHARSET_INFO *cs) const; }; diff --git a/sql/sql_type.h b/sql/sql_type.h index ce87c8e9d93..b047871a706 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -29,6 +29,7 @@ #include "sql_type_string.h" #include "sql_type_real.h" #include "compat56.h" +#include "filesort.h" C_MODE_START #include <ma_dyncol.h> C_MODE_END @@ -86,6 +87,7 @@ class handler; struct Schema_specification_st; struct TABLE; struct SORT_FIELD_ATTR; +struct SORT_FIELD; class Vers_history_point; class Virtual_column_info; class Conv_source; @@ -3332,6 +3334,14 @@ class Type_handler bool maybe_null, bool null_value, bool unsigned_flag, longlong value) const; + void store_sort_key_longlong(uchar *to, bool unsigned_flag, + longlong value) const; + + uint make_packed_sort_key_longlong(uchar *to, bool maybe_null, + bool null_value, bool unsigned_flag, + longlong value, + const SORT_FIELD_ATTR *sort_field) const; + bool Item_func_or_sum_illegal_param(const char *name) const; bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; bool check_null(const Item *item, st_value *value) const; @@ -3758,6 +3768,15 @@ class Type_handler virtual void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; + virtual bool is_packable() const { return false; } + + /* + create a compact sort key which can be compared with a comparison + function. They are called packed sort keys + */ + virtual uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const=0; virtual uint32 max_display_length(const Item *item) const= 0; virtual uint32 Item_decimal_notation_int_digits(const Item *item) const { return 0; } @@ -4155,6 +4174,13 @@ class Type_handler_row: public Type_handler { DBUG_ASSERT(0); } + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override + { + DBUG_ASSERT(0); + return 0; + } void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override { @@ -4483,6 +4509,9 @@ class Type_handler_real_result: public Type_handler_numeric const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; @@ -4590,6 +4619,9 @@ class Type_handler_decimal_result: public Type_handler_numeric const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; @@ -4840,6 +4872,9 @@ class Type_handler_int_result: public Type_handler_numeric TABLE_SHARE *share) const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void Column_definition_attributes_frm_pack(const Column_definition_attributes *at, uchar *buff) const override; @@ -4947,6 +4982,9 @@ class Type_handler_temporal_result: public Type_handler uchar *buff) const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; @@ -5036,9 +5074,13 @@ class Type_handler_string_result: public Type_handler CHARSET_INFO *cs) const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override; + bool is_packable()const override { return true; } bool union_element_finalize(const Item * item) const override; uint calc_key_length(const Column_definition &def) const override; bool Column_definition_prepare_stage1(THD *thd, @@ -6232,6 +6274,9 @@ class Type_handler_timestamp_common: public Type_handler_temporal_with_date const override; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const override; + uint make_packed_sort_key(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const override; void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const override;