diff options
author | Alexander Barkov <bar@mariadb.org> | 2015-03-12 18:12:15 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2015-03-12 18:12:15 +0400 |
commit | bb3115b256113097bcfd0d80213e160339e4b00b (patch) | |
tree | 2130426378c4762344bda6aad5f8e5d16d6cf770 | |
parent | 129c82bb5916d05ece4efad55e8dede3005559b4 (diff) | |
download | mariadb-git-bb3115b256113097bcfd0d80213e160339e4b00b.tar.gz |
MDEV-6990 GROUP_MIN_MAX optimization is not applied in some cases when it could
-rw-r--r-- | mysql-test/r/group_min_max.result | 54 | ||||
-rw-r--r-- | mysql-test/t/group_min_max.test | 36 | ||||
-rw-r--r-- | sql/field.cc | 32 | ||||
-rw-r--r-- | sql/field.h | 26 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 11 | ||||
-rw-r--r-- | sql/opt_range.cc | 34 |
6 files changed, 163 insertions, 30 deletions
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 9421ea9e740..07de4f7ac9d 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -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 +# diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 8c9be0ca8db..47d551f8241 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -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 # diff --git a/sql/field.cc b/sql/field.cc index 83560003128..57721d39d32 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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. */ @@ -5257,6 +5269,14 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d) return TIME_to_my_decimal(<ime, 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 @@ -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; diff --git a/sql/field.h b/sql/field.h index cac9a156a95..ef0fa2765a4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -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 { @@ -963,6 +964,9 @@ public: 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; @@ -1154,6 +1158,8 @@ public: 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) */ @@ -1581,6 +1587,12 @@ public: 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; + } }; @@ -1613,6 +1625,8 @@ public: { 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 @@ public: 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); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 685e9105aa3..7aaef893415 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -131,6 +131,11 @@ public: 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; + } }; @@ -419,6 +424,12 @@ public: { 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); + } }; /** diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3cac6e5139e..8f691f4e5dc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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 |