Skip to content

Commit

Permalink
MDEV-6989 BINARY and COLLATE xxx_bin comparisions are not used for op…
Browse files Browse the repository at this point in the history
…timization in some cases
  • Loading branch information
Alexander Barkov committed Mar 13, 2015
1 parent bd21058 commit 75d65b5
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 81 deletions.
4 changes: 2 additions & 2 deletions mysql-test/r/range.result
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a=binary 'aaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 11 NULL 2 Using index condition
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a='aaa' collate latin1_bin;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 11 NULL 2 Using index condition
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a='aaa' collate latin1_german1_ci;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL a NULL NULL NULL 9 Using where
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/range_mrr_icp.result
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,10 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a=binary 'aaa';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 11 NULL 2 Using index condition; Rowid-ordered scan
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a='aaa' collate latin1_bin;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range a a 11 NULL 2 Using index condition; Rowid-ordered scan
1 SIMPLE t1 ref a a 11 const 2 Using index condition
explain select * from t1 where a='aaa' collate latin1_german1_ci;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL a NULL NULL NULL 9 Using where
Expand Down
60 changes: 60 additions & 0 deletions mysql-test/r/type_varchar.result
Original file line number Diff line number Diff line change
Expand Up @@ -549,5 +549,65 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 index PRIMARY PRIMARY 22 NULL 2 Using where; Using index
DROP TABLE IF EXISTS t1,t2;
#
# MDEV-6989 BINARY and COLLATE xxx_bin comparisions are not used for optimization in some cases
#
CREATE TABLE t1 (c1 VARCHAR(20) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t1 VALUES ('a'),('b'),('c'),('d');
SELECT * FROM t1 WHERE c1=BINARY 'a';
c1
a
EXPLAIN SELECT * FROM t1 WHERE c1=BINARY 'a';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 22 const 1 Using index
SELECT * FROM t1 WHERE c1=_latin1'a' COLLATE latin1_bin;
c1
a
EXPLAIN SELECT * FROM t1 WHERE c1=_latin1'a' COLLATE latin1_bin;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 const PRIMARY PRIMARY 22 const 1 Using index
DROP TABLE t1;
CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin);
INSERT INTO t1 VALUES ('a');
CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t2 VALUES ('a'),('b');
SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
c1 c1
a a
EXPLAIN SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
1 SIMPLE t2 const PRIMARY PRIMARY 12 const 1 Using index
ALTER TABLE t1 MODIFY c1 VARBINARY(10);
SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
c1 c1
a a
EXPLAIN SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
1 SIMPLE t2 const PRIMARY PRIMARY 12 const 1 Using index
DROP TABLE t1, t2;
CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin);
INSERT INTO t1 VALUES ('a'),('c');
CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t2 VALUES ('a'),('b');
SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
c1
a
c
# t2 should be eliminated
EXPLAIN SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
ALTER TABLE t1 MODIFY c1 VARBINARY(10);
SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
c1
a
c
# t2 should be eliminated
EXPLAIN SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2
DROP TABLE t1,t2;
#
# End of 10.0 tests
#
36 changes: 36 additions & 0 deletions mysql-test/t/type_varchar.test
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,42 @@ SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.c1=t2.c1;
EXPLAIN SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.c1=t2.c1;
DROP TABLE IF EXISTS t1,t2;


--echo #
--echo # MDEV-6989 BINARY and COLLATE xxx_bin comparisions are not used for optimization in some cases
--echo #
CREATE TABLE t1 (c1 VARCHAR(20) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t1 VALUES ('a'),('b'),('c'),('d');
SELECT * FROM t1 WHERE c1=BINARY 'a';
EXPLAIN SELECT * FROM t1 WHERE c1=BINARY 'a';
SELECT * FROM t1 WHERE c1=_latin1'a' COLLATE latin1_bin;
EXPLAIN SELECT * FROM t1 WHERE c1=_latin1'a' COLLATE latin1_bin;
DROP TABLE t1;

CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin);
INSERT INTO t1 VALUES ('a');
CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t2 VALUES ('a'),('b');
SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
EXPLAIN SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
ALTER TABLE t1 MODIFY c1 VARBINARY(10);
SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
EXPLAIN SELECT * FROM t1, t2 WHERE t1.c1=t2.c1;
DROP TABLE t1, t2;

CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin);
INSERT INTO t1 VALUES ('a'),('c');
CREATE TABLE t2 (c1 VARCHAR(10) CHARACTER SET latin1, PRIMARY KEY(c1));
INSERT INTO t2 VALUES ('a'),('b');
SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
--echo # t2 should be eliminated
EXPLAIN SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
ALTER TABLE t1 MODIFY c1 VARBINARY(10);
SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
--echo # t2 should be eliminated
EXPLAIN SELECT t1.* FROM t1 LEFT JOIN t2 USING (c1);
DROP TABLE t1,t2;

--echo #
--echo # End of 10.0 tests
--echo #
97 changes: 88 additions & 9 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1246,11 +1246,23 @@ 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_keypart_ref(const Item_func *cond,
const Item *item) const
{
DBUG_ASSERT(cmp_type() != STRING_RESULT);
DBUG_ASSERT(cmp_type() != TIME_RESULT);
return item->cmp_type() != TIME_RESULT;
}


/*
This handles all numeric and BIT data types.
*/
bool Field::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
const Item *const_item) const
{
DBUG_ASSERT(cmp_type() != STRING_RESULT);
DBUG_ASSERT(cmp_type() != TIME_RESULT);
Expand Down Expand Up @@ -5270,8 +5282,15 @@ my_decimal *Field_temporal::val_decimal(my_decimal *d)
}


bool Field_temporal::can_optimize_keypart_ref(const Item_func *cond,
const Item *value) const
{
return true; // Field is of TIME_RESULT, which supersedes everything else.
}


bool Field_temporal::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
const Item *const_item) const
{
return true; // Field is of TIME_RESULT, which supersedes everything else.
}
Expand Down Expand Up @@ -6468,15 +6487,50 @@ uint32 Field_longstr::max_data_length() const
}


bool Field_longstr::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
bool
Field_longstr::cmp_to_string_with_same_collation(const Item_func *cond,
const Item *item) const
{
// Can't use indexes when comparing a string to a number or a date
if (const_item->cmp_type() != STRING_RESULT)
return false;
return item->cmp_type() == STRING_RESULT &&
charset() == cond->compare_collation();
}

// Don't use an index when comparing strings of different collations.
return charset() == cond->compare_collation();

bool
Field_longstr::cmp_to_string_with_stricter_collation(const Item_func *cond,
const Item *item) const
{
return item->cmp_type() == STRING_RESULT &&
(charset() == cond->compare_collation() ||
cond->compare_collation()->state & MY_CS_BINSORT);
}


bool Field_longstr::can_optimize_keypart_ref(const Item_func *cond,
const Item *item) const
{
DBUG_ASSERT(cmp_type() == STRING_RESULT);
return cmp_to_string_with_stricter_collation(cond, item);
}


bool Field_longstr::can_optimize_hash_join(const Item_func *cond,
const Item *item) const
{
DBUG_ASSERT(cmp_type() == STRING_RESULT);
return cmp_to_string_with_same_collation(cond, item);
}


bool Field_longstr::can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item) const
{
/*
Can't use indexes when comparing a string to a number or a date
Don't use an index when comparing strings of different collations.
*/
DBUG_ASSERT(cmp_type() == STRING_RESULT);
return cmp_to_string_with_same_collation(cond, const_item);
}


Expand Down Expand Up @@ -8489,6 +8543,31 @@ uint Field_num::is_equal(Create_field *new_field)
}


bool Field_enum::can_optimize_keypart_ref(const Item_func *cond,
const Item *item) const
{
DBUG_ASSERT(cmp_type() == INT_RESULT);
DBUG_ASSERT(result_type() == STRING_RESULT);

switch (item->cmp_type())
{
case TIME_RESULT:
return false;
case INT_RESULT:
case DECIMAL_RESULT:
case REAL_RESULT:
return true;
case STRING_RESULT:
return charset() == ((Item_func*)cond)->compare_collation();
case IMPOSSIBLE_RESULT:
case ROW_RESULT:
DBUG_ASSERT(0);
break;
}
return false;
}


/*
Bit field.
Expand Down
38 changes: 32 additions & 6 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_func;
class Item_bool_func2;

enum enum_check_fields
Expand Down Expand Up @@ -964,9 +965,21 @@ class Field
return (double) 0.5;
}

virtual bool can_optimize_keypart_ref(const Item_func *cond,
const Item *item) const;
virtual bool can_optimize_hash_join(const Item_func *cond,
const Item *item) const
{
return can_optimize_keypart_ref(cond, item);
}
virtual bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);

const Item *const_item) const;
bool can_optimize_outer_join_table_elimination(const Item_func *cond,
const Item *item) const
{
// Exactly the same rules with REF access
return can_optimize_keypart_ref(cond, item);
}
friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
friend class Copy_field;
Expand Down Expand Up @@ -1147,6 +1160,10 @@ class Field_longstr :public Field_str
return report_if_important_data(copier->source_end_pos(),
end, count_spaces);
}
bool cmp_to_string_with_same_collation(const Item_func *cond,
const Item *item) const;
bool cmp_to_string_with_stricter_collation(const Item_func *cond,
const Item *item) const;
public:
Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
Expand All @@ -1158,8 +1175,10 @@ 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_keypart_ref(const Item_func *cond, const Item *item) const;
bool can_optimize_hash_join(const Item_func *cond, const Item *item) const;
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
const Item *const_item) const;
};

/* base class for float and double and decimal (old one) */
Expand Down Expand Up @@ -1587,8 +1606,13 @@ 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_keypart_ref(const Item_func *cond, const Item *item) const
{
DBUG_ASSERT(0);
return false;
}
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
const Item *const_item) const
{
DBUG_ASSERT(0);
return false;
Expand Down Expand Up @@ -1625,8 +1649,9 @@ class Field_temporal: public Field {
{
return pos_in_interval_val_real(min, max);
}
bool can_optimize_keypart_ref(const Item_func *cond, const Item *item) const;
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item);
const Item *const_item) const;
};


Expand Down Expand Up @@ -2664,8 +2689,9 @@ 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_keypart_ref(const Item_func *cond, const Item *item) const;
bool can_optimize_group_min_max(const Item_bool_func2 *cond,
const Item *const_item)
const Item *const_item) const
{
/*
Can't use GROUP_MIN_MAX optimization for ENUM and SET,
Expand Down
22 changes: 1 addition & 21 deletions sql/opt_table_elimination.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1486,28 +1486,8 @@ void check_equality(Dep_analysis_context *ctx, Dep_module_expr **eq_mod,
left->real_item()->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*)left->real_item())->field;
if (right->cmp_type() == TIME_RESULT && field->cmp_type() != TIME_RESULT)
if (!field->can_optimize_outer_join_table_elimination(cond, right))
return;
if (field->result_type() == STRING_RESULT)
{
if (right->result_type() != STRING_RESULT)
{
if (field->cmp_type() != right->result_type())
return;
}
else
{
/*
We can't assume there's a functional dependency if the effective
collation of the operation differ from the field collation.
*/
if ((field->cmp_type() == STRING_RESULT ||
field->real_type() == MYSQL_TYPE_ENUM ||
field->real_type() == MYSQL_TYPE_SET) &&
field->charset() != cond->compare_collation())
return;
}
}
Dep_value_field *field_val;
if ((field_val= ctx->get_field_value(field)))
add_module_expr(ctx, eq_mod, and_level, field_val, right, NULL);
Expand Down
Loading

0 comments on commit 75d65b5

Please sign in to comment.