summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc60
1 files changed, 42 insertions, 18 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7ee1762295f..4a32ca34790 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13017,6 +13017,34 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
}
+/**
+ Find shortest key suitable for full table scan.
+
+ @param table Table to scan
+ @param usable_keys Allowed keys
+
+ @note
+ As far as
+ 1) clustered primary key entry data set is a set of all record
+ fields (key fields and not key fields) and
+ 2) secondary index entry data is a union of its key fields and
+ primary key fields (at least InnoDB and its derivatives don't
+ duplicate primary key fields there, even if the primary and
+ the secondary keys have a common subset of key fields),
+ then secondary index entry data is always a subset of primary key entry.
+ Unfortunately, key_info[nr].key_length doesn't show the length
+ of key/pointer pair but a sum of key field lengths only, thus
+ we can't estimate index IO volume comparing only this key_length
+ value of secondary keys and clustered PK.
+ So, try secondary keys first, and choose PK only if there are no
+ usable secondary covering keys or found best secondary key include
+ all table fields (i.e. same as PK):
+
+ @return
+ MAX_KEY no suitable key found
+ key index otherwise
+*/
+
uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
uint best= MAX_KEY;
@@ -13029,23 +13057,6 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
uint min_length= (uint) ~0;
for (uint nr=0; nr < table->s->keys ; nr++)
{
- /*
- As far as
- 1) clustered primary key entry data set is a set of all record
- fields (key fields and not key fields) and
- 2) secondary index entry data is a union of its key fields and
- primary key fields (at least InnoDB and its derivatives don't
- duplicate primary key fields there, even if the primary and
- the secondary keys have a common subset of key fields),
- then secondary index entry data is always a subset of primary key
- entry, and the PK is always longer.
- Unfortunately, key_info[nr].key_length doesn't show the length
- of key/pointer pair but a sum of key field lengths only, thus
- we can't estimate index IO volume comparing only this key_length
- value of seconday keys and clustered PK.
- So, try secondary keys first, and choose PK only if there are no
- usable secondary covering keys:
- */
if (nr == usable_clustered_pk)
continue;
if (usable_keys->is_set(nr))
@@ -13058,7 +13069,20 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
}
}
}
- return best != MAX_KEY ? best : usable_clustered_pk;
+ if (usable_clustered_pk != MAX_KEY)
+ {
+ /*
+ If the primary key is clustered and found shorter key covers all table
+ fields then primary key scan normally would be faster because amount of
+ data to scan is the same but PK is clustered.
+ It's safe to compare key parts with table fields since duplicate key
+ parts aren't allowed.
+ */
+ if (best == MAX_KEY ||
+ table->key_info[best].key_parts >= table->s->fields)
+ best= usable_clustered_pk;
+ }
+ return best;
}
/**