From 6d0425b18df7468036a1bbf6d781d624a28e2fb3 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Mon, 10 May 2010 09:23:23 +0200 Subject: Bug#50939: Loose Index Scan unduly relies on engine to remember range endpoints The Loose Index Scan optimization keeps track of a sequence of intervals. For the current interval it maintains the current interval's endpoints. But the maximum endpoint was not stored in the SQL layer; rather, it relied on the storage engine to retain this value in-between reads. By coincidence this holds for MyISAM and InnoDB. Not for the partitioning engine, however. Fixed by making the key values iterator (QUICK_RANGE_SELECT) keep track of the current maximum endpoint. This is also more efficient as we save a call through the handler API in case of open-ended intervals. The code to calculate endpoints was extracted into separate methods in QUICK_RANGE_SELECT, and it was possible to get rid of some code duplication as part of fix. --- sql/opt_range.h | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) (limited to 'sql/opt_range.h') diff --git a/sql/opt_range.h b/sql/opt_range.h index 8d2ba1bb0a6..e7d8297faf8 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -65,6 +65,85 @@ class QUICK_RANGE :public Sql_alloc { dummy=0; #endif } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the minimum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + + @param prefix_length The length of the search key prefix to be used for + lookup. + + @param keypart_map A set (bitmap) of keyparts to be used. + */ + void make_min_endpoint(key_range *kr, uint prefix_length, + key_part_map keypart_map) { + make_min_endpoint(kr); + kr->length= min(kr->length, prefix_length); + kr->keypart_map&= keypart_map; + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the minimum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + */ + void make_min_endpoint(key_range *kr) { + kr->key= (const uchar*)min_key; + kr->length= min_length; + kr->keypart_map= min_keypart_map; + kr->flag= ((flag & NEAR_MIN) ? HA_READ_AFTER_KEY : + (flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the maximum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + + @param prefix_length The length of the search key prefix to be used for + lookup. + + @param keypart_map A set (bitmap) of keyparts to be used. + */ + void make_max_endpoint(key_range *kr, uint prefix_length, + key_part_map keypart_map) { + make_max_endpoint(kr); + kr->length= min(kr->length, prefix_length); + kr->keypart_map&= keypart_map; + } + + /** + Initalizes a key_range object for communication with storage engine. + + This function facilitates communication with the Storage Engine API by + translating the maximum endpoint of the interval represented by this + QUICK_RANGE into an index range endpoint specifier for the engine. + + @param Pointer to an uninitialized key_range C struct. + */ + void make_max_endpoint(key_range *kr) { + kr->key= (const uchar*)max_key; + kr->length= max_length; + kr->keypart_map= max_keypart_map; + /* + We use READ_AFTER_KEY here because if we are reading on a key + prefix we want to find all keys with this prefix + */ + kr->flag= (flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); + } }; @@ -331,7 +410,7 @@ public: int reset(void); int get_next(); void range_end(); - int get_next_prefix(uint prefix_length, key_part_map keypart_map, + int get_next_prefix(uint prefix_length, uint group_key_parts, uchar *cur_prefix); bool reverse_sorted() { return 0; } bool unique_key_range(); @@ -611,7 +690,7 @@ private: uchar *record; /* Buffer where the next record is returned. */ uchar *tmp_record; /* Temporary storage for next_min(), next_max(). */ uchar *group_prefix; /* Key prefix consisting of the GROUP fields. */ - uint group_prefix_len; /* Length of the group prefix. */ + const uint group_prefix_len; /* Length of the group prefix. */ uint group_key_parts; /* A number of keyparts in the group prefix */ uchar *last_prefix; /* Prefix of the last group for detecting EOF. */ bool have_min; /* Specify whether we are computing */ -- cgit v1.2.1 From 2b734bbee9aeb98a64a5b59808f56342819053a7 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Thu, 24 Jun 2010 15:21:23 +0200 Subject: Bug#41660: Sort-index_merge for non-first join table may require O(#scans) memory When an index merge operation was restarted, it would re-allocate the Unique object controlling the duplicate row ID elimination. Fixed by making the Unique object a member of QUICK_INDEX_MERGE_SELECT and thus reusing it throughout the lifetime of this object. --- sql/opt_range.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql/opt_range.h') diff --git a/sql/opt_range.h b/sql/opt_range.h index e7d8297faf8..edae1e4114a 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -500,6 +500,7 @@ public: class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I { + Unique *unique; public: QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table); ~QUICK_INDEX_MERGE_SELECT(); @@ -684,7 +685,7 @@ private: class QUICK_GROUP_MIN_MAX_SELECT : public QUICK_SELECT_I { private: - handler *file; /* The handler used to get data. */ + handler * const file; /* The handler used to get data. */ JOIN *join; /* Descriptor of the current query */ KEY *index_info; /* The index chosen for data access */ uchar *record; /* Buffer where the next record is returned. */ -- cgit v1.2.1