Skip to content

Commit

Permalink
MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases whe…
Browse files Browse the repository at this point in the history
…n it could
  • Loading branch information
Alexander Barkov committed Mar 12, 2015
1 parent 129c82b commit bb3115b
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 30 deletions.
54 changes: 54 additions & 0 deletions mysql-test/r/group_min_max.result
Original file line number Diff line number Diff line change
Expand Up @@ -3727,3 +3727,57 @@ DROP TABLE t1;
#
# 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
#
36 changes: 36 additions & 0 deletions mysql-test/t/group_min_max.test
Original file line number Diff line number Diff line change
Expand Up @@ -1524,3 +1524,39 @@ DROP TABLE t1;
--echo # End of 10.0 tests
--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 #
32 changes: 32 additions & 0 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -5257,6 +5269,14 @@ my_decimal *Field_temporal::val_decimal(my_decimal *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
** In string context: HH:MM:SS
Expand Down Expand Up @@ -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)
{
ASSERT_COLUMN_MARKED_FOR_READ;
Expand Down
26 changes: 26 additions & 0 deletions sql/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Relay_log_info;
class Field;
class Column_statistics;
class Column_statistics_collected;
class Item_bool_func2;

enum enum_check_fields
{
Expand Down Expand Up @@ -963,6 +964,9 @@ class Field
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,
ulonglong auto_increment_value);
friend class Copy_field;
Expand Down Expand Up @@ -1154,6 +1158,8 @@ class Field_longstr :public Field_str
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
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) */
Expand Down Expand Up @@ -1581,6 +1587,12 @@ class Field_null :public Field_str {
uint size_of() const { return sizeof(*this); }
uint32 max_display_length() { return 4; }
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;
}
};


Expand Down Expand Up @@ -1613,6 +1625,8 @@ class Field_temporal: public Field {
{
return pos_in_interval_val_real(min, max);
}
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
};


Expand Down Expand Up @@ -2650,6 +2664,18 @@ class Field_enum :public Field_str {
virtual const uchar *unpack(uchar *to, const uchar *from,
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:
int do_save_field_metadata(uchar *first_byte);
uint is_equal(Create_field *new_field);
Expand Down
11 changes: 11 additions & 0 deletions sql/item_cmpfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ class Item_bool_func :public Item_int_func
bool is_bool_type() { return true; }
void fix_length_and_dec() { decimals=0; max_length=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;
}
};


Expand Down Expand Up @@ -419,6 +424,12 @@ class Item_bool_rowready_func2 :public Item_bool_func2
{
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);
}
};

/**
Expand Down
34 changes: 4 additions & 30 deletions sql/opt_range.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13412,39 +13412,13 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item,
if (!simple_pred(pred, args, &inv))
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[1]->cmp_type() == TIME_RESULT &&
min_max_arg_item->field->cmp_type() != TIME_RESULT)
DBUG_ASSERT(pred->is_bool_type());
Item_bool_func *bool_func= (Item_bool_func*) pred;
if (!bool_func->can_optimize_group_min_max(min_max_arg_item,
args[1]))
DBUG_RETURN(FALSE);

/*
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);
}
}
else
Expand Down

0 comments on commit bb3115b

Please sign in to comment.