diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 07b4c71cbe3..7be0479a5a8 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2858,9 +2858,10 @@ COUNT(DISTINCT a, b + 0) 16 EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by +1 SIMPLE t1 index NULL a 10 NULL 16 Using index SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10; COUNT(DISTINCT a) +2 EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 16 @@ -2994,7 +2995,7 @@ WHERE b = 13 AND c = 42 GROUP BY a; a COUNT(DISTINCT a) SUM(DISTINCT a) EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range NULL a 10 NULL 9 Using where; Using index for group-by +1 SIMPLE t2 index NULL a 15 NULL 16 Using where; Using index SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; COUNT(DISTINCT a, b) SUM(DISTINCT a) 0 NULL diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index fa52da63195..2b38b60ef3c 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1207,6 +1207,8 @@ EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2 WHERE b = 13 AND c = 42 GROUP BY a; +# This query could have been resolved using loose index scan since the second +# part of count(..) is defined by a constant predicate EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42; diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index f08a6a07bce..449fde37bee 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -71,6 +71,7 @@ public: my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); } my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } + my_bool operator!=(const Bitmap& map2) const { return !(*this == map2); } char *print(char *buf) const { char *s=buf; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0cb6981bfd8..fbb5d00e7a8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4204,8 +4204,23 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) Optionally (if out_args is supplied) will push the arguments of AGGFN(DISTINCT) to the list + Check for every COUNT(DISTINCT), AVG(DISTINCT) or + SUM(DISTINCT). These can be resolved by Loose Index Scan as long + as all the aggregate distinct functions refer to the same + fields. Thus: + + SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT b, a)... => can use LIS + SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT a) ... => can use LIS + SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT a) ... => cannot use LIS + SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT b) ... => cannot use LIS + etc. + @param join the join to check - @param[out] out_args list of aggregate function arguments + @param[out] out_args Collect the arguments of the aggregate functions + to a list. We don't worry about duplicates as + these will be sorted out later in + get_best_group_min_max. + @return does the query qualify for indexed AGGFN(DISTINCT) @retval true it does @retval false AGGFN(DISTINCT) must apply distinct in it. @@ -4216,6 +4231,7 @@ is_indexed_agg_distinct(JOIN *join, List *out_args) { Item_sum **sum_item_ptr; bool result= false; + Field_map first_aggdistinct_fields; if (join->tables != 1 || /* reference more than 1 table */ join->select_distinct || /* or a DISTINCT */ @@ -4228,6 +4244,7 @@ is_indexed_agg_distinct(JOIN *join, List *out_args) for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++) { Item_sum *sum_item= *sum_item_ptr; + Field_map cur_aggdistinct_fields; Item *expr; /* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */ switch (sum_item->sum_func()) @@ -4257,15 +4274,23 @@ is_indexed_agg_distinct(JOIN *join, List *out_args) if (expr->real_item()->type() != Item::FIELD_ITEM) return false; - /* - If we came to this point the AGGFN(DISTINCT) loose index scan - optimization is applicable - */ + Item_field* item= static_cast(expr->real_item()); if (out_args) - out_args->push_back((Item_field *) expr->real_item()); + out_args->push_back(item); + + cur_aggdistinct_fields.set_bit(item->field->field_index); result= true; } + /* + If there are multiple aggregate functions, make sure that they all + refer to exactly the same set of columns. + */ + if (first_aggdistinct_fields.is_clear_all()) + first_aggdistinct_fields.merge(cur_aggdistinct_fields); + else if (first_aggdistinct_fields != cur_aggdistinct_fields) + return false; } + return result; } diff --git a/sql/table.h b/sql/table.h index 9a85dd83b13..5d4bb654263 100644 --- a/sql/table.h +++ b/sql/table.h @@ -894,6 +894,9 @@ enum index_hint_type INDEX_HINT_FORCE }; +/* Bitmap of table's fields */ +typedef Bitmap Field_map; + struct TABLE { TABLE() {} /* Remove gcc warning */