Skip to content

Commit 7493ae4

Browse files
author
Steinar H. Gunderson
committed
Bug #30473261: CONVERT THE INDEX SUBQUERY ENGINES INTO USING THE ITERATOR EXECUTOR [patch 3/10, hashed refs]
Make RefIterator support hashed refs. Most index lookups (ref accesses) follow a pattern where the index' parts are matched 1:1 with a set of items, e.g. an index on (a,b) could have a lookup a=3,b=t1.other_b. However, as a special case, temporary tables may need indexes over a set of fields that are so large that they cannot be part of a unique index (e.g. blobs, or a large set of fields). In this case, the index is over a single column (a non-unique numeric hash of all the fields involved), and the TABLE_REF construction takes a rather different form, with each field being hashed into this column. We need to handle this correctly in RefIterator, and also print this correctly in EXPLAIN, even though we no longer have a 1:1 match between parts of the lookup key (TABLE_REF) and fields in the index (key_parts in KEY). This is needed for the next patch in the series. Stricly speaking, it only uses hashed refs in (forward-scanning) RefIterator, but for orthogonality, we add it to all paths where it is easy to do so. Change-Id: If8442551d29ac76914e94470169a233812052638
1 parent a5f60bf commit 7493ae4

File tree

3 files changed

+56
-9
lines changed

3 files changed

+56
-9
lines changed

Diff for: sql/item_subselect.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -3346,6 +3346,10 @@ bool subselect_hash_sj_engine::setup(THD *thd, List<Item> *tmp_columns) {
33463346
!(tab->ref().items = (Item **)thd->alloc(sizeof(Item *) * tmp_key_parts)))
33473347
return true;
33483348

3349+
if (tmp_table->hash_field) {
3350+
tab->ref().keypart_hash = &hash;
3351+
}
3352+
33493353
uchar *cur_ref_buff = tab->ref().key_buff;
33503354

33513355
/*
@@ -3399,11 +3403,11 @@ bool subselect_hash_sj_engine::setup(THD *thd, List<Item> *tmp_columns) {
33993403
return true;
34003404
}
34013405

3402-
if (tmp_table->hash_field)
3406+
if (tmp_table->hash_field) {
34033407
tab->ref().key_copy[part_no] = new (thd->mem_root) store_key_hash_item(
34043408
thd, field, cur_ref_buff, nullptr, field->pack_length(),
34053409
tab->ref().items[part_no], &hash);
3406-
else
3410+
} else {
34073411
tab->ref().key_copy[part_no] = new (thd->mem_root) store_key_item(
34083412
thd, field,
34093413
/* TODO:
@@ -3414,6 +3418,7 @@ bool subselect_hash_sj_engine::setup(THD *thd, List<Item> *tmp_columns) {
34143418
*/
34153419
cur_ref_buff + (nullable ? 1 : 0), nullable ? cur_ref_buff : nullptr,
34163420
key_parts[part_no].length, tab->ref().items[part_no]);
3421+
}
34173422
if (nullable && // nullable column in tmp table,
34183423
// and UNKNOWN should not be interpreted as FALSE
34193424
!item_in->abort_on_null) {

Diff for: sql/sql_executor.cc

+42-7
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,10 @@
132132
#include "template_utils.h"
133133
#include "thr_lock.h"
134134

135+
using std::make_pair;
135136
using std::max;
136137
using std::min;
138+
using std::pair;
137139
using std::string;
138140
using std::unique_ptr;
139141
using std::vector;
@@ -167,6 +169,8 @@ static bool alloc_group_fields(JOIN *join, ORDER *group);
167169
static void SetCostOnTableIterator(const Cost_model_server &cost_model,
168170
const POSITION *pos, bool is_after_filter,
169171
RowIterator *iterator);
172+
static inline pair<uchar *, key_part_map> FindKeyBufferAndMap(
173+
const TABLE_REF *ref);
170174

171175
/**
172176
Evaluates HAVING condition
@@ -190,6 +194,21 @@ static constexpr size_t MAX_RECORD_BUFFER_SIZE = 128 * 1024; // 128KB
190194
string RefToString(const TABLE_REF &ref, const KEY *key, bool include_nulls) {
191195
string ret;
192196

197+
if (ref.keypart_hash != nullptr) {
198+
DBUG_ASSERT(!include_nulls);
199+
ret = key->key_part[0].field->field_name;
200+
ret += "=hash(";
201+
for (unsigned key_part_idx = 0; key_part_idx < ref.key_parts;
202+
++key_part_idx) {
203+
if (key_part_idx != 0) {
204+
ret += ", ";
205+
}
206+
ret += ItemToString(ref.items[key_part_idx]);
207+
}
208+
ret += ")";
209+
return ret;
210+
}
211+
193212
const uchar *key_buff = ref.key_buff;
194213

195214
for (unsigned key_part_idx = 0; key_part_idx < ref.key_parts;
@@ -4845,9 +4864,10 @@ int EQRefIterator::Read() {
48454864
return -1;
48464865
}
48474866

4867+
pair<uchar *, key_part_map> key_buff_and_map = FindKeyBufferAndMap(m_ref);
48484868
int error = table()->file->ha_index_read_map(
4849-
table()->record[0], m_ref->key_buff,
4850-
make_prev_keypart_map(m_ref->key_parts), HA_READ_KEY_EXACT);
4869+
table()->record[0], key_buff_and_map.first, key_buff_and_map.second,
4870+
HA_READ_KEY_EXACT);
48514871
if (error) {
48524872
return HandleError(error);
48534873
}
@@ -5021,9 +5041,11 @@ int RefIterator<false>::Read() { // Forward read.
50215041
table()->set_no_row();
50225042
return -1;
50235043
}
5044+
5045+
pair<uchar *, key_part_map> key_buff_and_map = FindKeyBufferAndMap(m_ref);
50245046
int error = table()->file->ha_index_read_map(
5025-
table()->record[0], m_ref->key_buff,
5026-
make_prev_keypart_map(m_ref->key_parts), HA_READ_KEY_EXACT);
5047+
table()->record[0], key_buff_and_map.first, key_buff_and_map.second,
5048+
HA_READ_KEY_EXACT);
50275049
if (error) {
50285050
return HandleError(error);
50295051
}
@@ -5046,6 +5068,8 @@ int RefIterator<false>::Read() { // Forward read.
50465068
*/
50475069
template <>
50485070
int RefIterator<true>::Read() { // Reverse read.
5071+
assert(m_ref->keypart_hash == nullptr);
5072+
50495073
if (m_first_record_since_init) {
50505074
m_first_record_since_init = false;
50515075

@@ -5427,15 +5451,17 @@ int RefOrNullIterator::Read() {
54275451
}
54285452
}
54295453

5454+
pair<uchar *, key_part_map> key_buff_and_map = FindKeyBufferAndMap(m_ref);
5455+
54305456
int error;
54315457
if (m_reading_first_row) {
54325458
m_reading_first_row = false;
54335459
error = table()->file->ha_index_read_map(
5434-
table()->record[0], m_ref->key_buff,
5435-
make_prev_keypart_map(m_ref->key_parts), HA_READ_KEY_EXACT);
5460+
table()->record[0], key_buff_and_map.first, key_buff_and_map.second,
5461+
HA_READ_KEY_EXACT);
54365462
} else {
54375463
error = table()->file->ha_index_next_same(
5438-
table()->record[0], m_ref->key_buff, m_ref->key_length);
5464+
table()->record[0], key_buff_and_map.first, key_buff_and_map.second);
54395465
}
54405466

54415467
if (error == 0) {
@@ -9220,3 +9246,12 @@ int TableValueConstructorIterator::Read() {
92209246
++*m_examined_rows;
92219247
return 0;
92229248
}
9249+
9250+
static inline pair<uchar *, key_part_map> FindKeyBufferAndMap(
9251+
const TABLE_REF *ref) {
9252+
if (ref->keypart_hash != nullptr) {
9253+
return make_pair(pointer_cast<uchar *>(ref->keypart_hash), key_part_map{1});
9254+
} else {
9255+
return make_pair(ref->key_buff, make_prev_keypart_map(ref->key_parts));
9256+
}
9257+
}

Diff for: sql/sql_opt_exec_shared.h

+7
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ struct TABLE_REF {
111111
*/
112112
bool disable_cache;
113113

114+
/*
115+
If non-nullptr, all the fields are hashed together through functions
116+
in store_key (with the result being put into this field), as opposed to
117+
being matched against individual fields in the associated KEY's key parts.
118+
*/
119+
ulonglong *keypart_hash = nullptr;
120+
114121
TABLE_REF()
115122
: key_err(true),
116123
key_parts(0),

0 commit comments

Comments
 (0)