Commit bb3115b2 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could

parent 129c82bb
...@@ -3727,3 +3727,57 @@ DROP TABLE t1; ...@@ -3727,3 +3727,57 @@ DROP TABLE t1;
# #
# End of 10.0 tests # End of 10.0 tests
# #
#
# Start of 10.1 tests
#
#
# MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
#
CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a)) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,'2001-01-01');
INSERT INTO t1 VALUES (1,'2001-01-02');
INSERT INTO t1 VALUES (1,'2001-01-03');
INSERT INTO t1 VALUES (1,'2001-01-04');
INSERT INTO t1 VALUES (2,'2001-01-01');
INSERT INTO t1 VALUES (2,'2001-01-02');
INSERT INTO t1 VALUES (2,'2001-01-03');
INSERT INTO t1 VALUES (2,'2001-01-04');
INSERT INTO t1 VALUES (3,'2001-01-01');
INSERT INTO t1 VALUES (3,'2001-01-02');
INSERT INTO t1 VALUES (3,'2001-01-03');
INSERT INTO t1 VALUES (3,'2001-01-04');
INSERT INTO t1 VALUES (4,'2001-01-01');
INSERT INTO t1 VALUES (4,'2001-01-02');
INSERT INTO t1 VALUES (4,'2001-01-03');
INSERT INTO t1 VALUES (4,'2001-01-04');
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL id 8 NULL 9 Using where; Using index for group-by
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
id MIN(a) MAX(a)
1 2001-01-04 2001-01-04
2 2001-01-04 2001-01-04
3 2001-01-04 2001-01-04
4 2001-01-04 2001-01-04
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
id MIN(a) MAX(a)
1 2001-01-04 2001-01-04
2 2001-01-04 2001-01-04
3 2001-01-04 2001-01-04
4 2001-01-04 2001-01-04
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
id MIN(a) MAX(a)
1 2001-01-04 2001-01-04
2 2001-01-04 2001-01-04
3 2001-01-04 2001-01-04
4 2001-01-04 2001-01-04
DROP TABLE t1;
#
# End of 10.1 tests
#
...@@ -1524,3 +1524,39 @@ DROP TABLE t1; ...@@ -1524,3 +1524,39 @@ DROP TABLE t1;
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #
--echo #
--echo # Start of 10.1 tests
--echo #
--echo #
--echo # MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
--echo #
CREATE TABLE t1 (id INT NOT NULL, a DATE, KEY(id,a)) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1,'2001-01-01');
INSERT INTO t1 VALUES (1,'2001-01-02');
INSERT INTO t1 VALUES (1,'2001-01-03');
INSERT INTO t1 VALUES (1,'2001-01-04');
INSERT INTO t1 VALUES (2,'2001-01-01');
INSERT INTO t1 VALUES (2,'2001-01-02');
INSERT INTO t1 VALUES (2,'2001-01-03');
INSERT INTO t1 VALUES (2,'2001-01-04');
INSERT INTO t1 VALUES (3,'2001-01-01');
INSERT INTO t1 VALUES (3,'2001-01-02');
INSERT INTO t1 VALUES (3,'2001-01-03');
INSERT INTO t1 VALUES (3,'2001-01-04');
INSERT INTO t1 VALUES (4,'2001-01-01');
INSERT INTO t1 VALUES (4,'2001-01-02');
INSERT INTO t1 VALUES (4,'2001-01-03');
INSERT INTO t1 VALUES (4,'2001-01-04');
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>='2001-01-04' GROUP BY id;
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104.0 GROUP BY id;
SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id;
DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
--echo #
...@@ -1246,6 +1246,18 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset) ...@@ -1246,6 +1246,18 @@ double Field::pos_in_interval_val_str(Field *min, Field *max, uint data_offset)
} }
/*
This handles all numeric and BIT data types.
*/
bool Field::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
{
DBUG_ASSERT(cmp_type() != STRING_RESULT);
DBUG_ASSERT(cmp_type() != TIME_RESULT);
return const_item->cmp_type() != TIME_RESULT;
}
/** /**
Numeric fields base class constructor. Numeric fields base class constructor.
*/ */
...@@ -5257,6 +5269,14 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d) ...@@ -5257,6 +5269,14 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d)
return TIME_to_my_decimal(&ltime, d); return TIME_to_my_decimal(&ltime, d);
} }
bool Field_temporal::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
{
return true; // Field is of TIME_RESULT, which supersedes everything else.
}
/**************************************************************************** /****************************************************************************
** time type ** time type
** In string context: HH:MM:SS ** In string context: HH:MM:SS
...@@ -6448,6 +6468,18 @@ uint32 Field_longstr::max_data_length() const ...@@ -6448,6 +6468,18 @@ uint32 Field_longstr::max_data_length() const
} }
bool Field_longstr::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
{
// Can't use indexes when comparing a string to a number or a date
if (const_item->cmp_type() != STRING_RESULT)
return false;
// Don't use an index when comparing strings of different collations.
return charset() == ((Item_bool_func2*) cond)->compare_collation();
}
double Field_string::val_real(void) double Field_string::val_real(void)
{ {
ASSERT_COLUMN_MARKED_FOR_READ; ASSERT_COLUMN_MARKED_FOR_READ;
......
...@@ -39,6 +39,7 @@ class Relay_log_info; ...@@ -39,6 +39,7 @@ class Relay_log_info;
class Field; class Field;
class Column_statistics; class Column_statistics;
class Column_statistics_collected; class Column_statistics_collected;
class Item_bool_func2;
enum enum_check_fields enum enum_check_fields
{ {
...@@ -963,6 +964,9 @@ class Field ...@@ -963,6 +964,9 @@ class Field
return (double) 0.5; return (double) 0.5;
} }
virtual bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
friend int cre_myisam(char * name, register TABLE *form, uint options, friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value); ulonglong auto_increment_value);
friend class Copy_field; friend class Copy_field;
...@@ -1154,6 +1158,8 @@ class Field_longstr :public Field_str ...@@ -1154,6 +1158,8 @@ class Field_longstr :public Field_str
int store_decimal(const my_decimal *d); int store_decimal(const my_decimal *d);
uint32 max_data_length() const; uint32 max_data_length() const;
bool match_collation_to_optimize_range() const { return true; } bool match_collation_to_optimize_range() const { return true; }
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
}; };
/* base class for float and double and decimal (old one) */ /* base class for float and double and decimal (old one) */
...@@ -1581,6 +1587,12 @@ class Field_null :public Field_str { ...@@ -1581,6 +1587,12 @@ class Field_null :public Field_str {
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
uint32 max_display_length() { return 4; } uint32 max_display_length() { return 4; }
void move_field_offset(my_ptrdiff_t ptr_diff) {} void move_field_offset(my_ptrdiff_t ptr_diff) {}
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
{
DBUG_ASSERT(0);
return false;
}
}; };
...@@ -1613,6 +1625,8 @@ class Field_temporal: public Field { ...@@ -1613,6 +1625,8 @@ class Field_temporal: public Field {
{ {
return pos_in_interval_val_real(min, max); return pos_in_interval_val_real(min, max);
} }
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
}; };
...@@ -2650,6 +2664,18 @@ class Field_enum :public Field_str { ...@@ -2650,6 +2664,18 @@ class Field_enum :public Field_str {
virtual const uchar *unpack(uchar *to, const uchar *from, virtual const uchar *unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data); const uchar *from_end, uint param_data);
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
{
/*
Can't use GROUP_MIN_MAX optimization for ENUM and SET,
because the values are stored as numbers in index,
while MIN() and MAX() work as strings.
It would return the records with min and max enum numeric indexes.
"Bug#45300 MAX() and ENUM type" should be fixed first.
*/
return false;
}
private: private:
int do_save_field_metadata(uchar *first_byte); int do_save_field_metadata(uchar *first_byte);
uint is_equal(Create_field *new_field); uint is_equal(Create_field *new_field);
......
...@@ -131,6 +131,11 @@ class Item_bool_func :public Item_int_func ...@@ -131,6 +131,11 @@ class Item_bool_func :public Item_int_func
bool is_bool_type() { return true; } bool is_bool_type() { return true; }
void fix_length_and_dec() { decimals=0; max_length=1; } void fix_length_and_dec() { decimals=0; max_length=1; }
uint decimal_precision() const { return 1; } uint decimal_precision() const { return 1; }
virtual bool can_optimize_group_min_max(Item_field *min_max_arg_item,
const Item *const_item) const
{
return false;
}
}; };
...@@ -419,6 +424,12 @@ class Item_bool_rowready_func2 :public Item_bool_func2 ...@@ -419,6 +424,12 @@ class Item_bool_rowready_func2 :public Item_bool_func2
{ {
return (*arg != NULL); return (*arg != NULL);
} }
bool can_optimize_group_min_max(Item_field *min_max_arg_item,
const Item *const_item) const
{
return min_max_arg_item->field->can_optimize_group_min_max(this,
const_item);
}
}; };
/** /**
......
...@@ -13412,38 +13412,12 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item, ...@@ -13412,38 +13412,12 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item,
if (!simple_pred(pred, args, &inv)) if (!simple_pred(pred, args, &inv))
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
/* Check for compatible string comparisons - similar to get_mm_leaf. */
if (args[0] && args[1] && !args[2]) // this is a binary function if (args[0] && args[1] && !args[2]) // this is a binary function
{ {
if (args[1]->cmp_type() == TIME_RESULT && DBUG_ASSERT(pred->is_bool_type());
min_max_arg_item->field->cmp_type() != TIME_RESULT) Item_bool_func *bool_func= (Item_bool_func*) pred;
DBUG_RETURN(FALSE); if (!bool_func->can_optimize_group_min_max(min_max_arg_item,
args[1]))
/*
Can't use GROUP_MIN_MAX optimization for ENUM and SET,
because the values are stored as numbers in index,
while MIN() and MAX() work as strings.
It would return the records with min and max enum numeric indexes.
"Bug#45300 MAX() and ENUM type" should be fixed first.
*/
if (min_max_arg_item->field->real_type() == MYSQL_TYPE_ENUM ||
min_max_arg_item->field->real_type() == MYSQL_TYPE_SET)
DBUG_RETURN(FALSE);
if (min_max_arg_item->result_type() == STRING_RESULT &&
/*
Don't use an index when comparing strings of different collations.
*/
((args[1]->result_type() == STRING_RESULT &&
image_type == Field::itRAW &&
min_max_arg_item->field->charset() !=
pred->compare_collation()) ||
/*
We can't always use indexes when comparing a string index to a
number.
*/
(args[1]->result_type() != STRING_RESULT &&
min_max_arg_item->field->cmp_type() != args[1]->result_type())))
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment