diff options
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r-- | sql/opt_range.cc | 351 |
1 files changed, 181 insertions, 170 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7e432aca42a..bff5bd371b6 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -328,8 +328,6 @@ public: uint *imerge_cost_buff; /* buffer for index_merge cost estimates */ uint imerge_cost_buff_size; /* size of the buffer */ - /* TRUE if last checked tree->key can be used for ROR-scan */ - bool is_ror_scan; /* Number of ranges in the last checked tree->key */ uint n_ranges; uint8 first_null_comp; /* first null component if any, 0 - otherwise */ @@ -351,7 +349,7 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts); static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, SEL_ARG *tree, bool update_tbl_stats, uint *mrr_flags, uint *bufsize, - Cost_estimate *cost); + Cost_estimate *cost, bool *is_ror_scan); QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, SEL_ARG *key_tree, uint mrr_flags, @@ -431,16 +429,18 @@ static int and_range_trees(RANGE_OPT_PARAM *param, static bool remove_nonrange_trees(RANGE_OPT_PARAM *param, SEL_TREE *tree); static void print_key_value(String *out, const KEY_PART_INFO *key_part, - const uchar *key); + const uchar* key, uint length); +static void print_keyparts_name(String *out, const KEY_PART_INFO *key_part, + uint n_keypart, key_part_map keypart_map); -static void append_range_all_keyparts(Json_writer_array *range_trace, - String *range_string, - String *range_so_far, const SEL_ARG *keypart, - const KEY_PART_INFO *key_parts); +static void trace_ranges(Json_writer_array *range_trace, + PARAM *param, uint idx, + SEL_ARG *keypart, + const KEY_PART_INFO *key_parts); static -void append_range(String *out, const KEY_PART_INFO *key_parts, - const uchar *min_key, const uchar *max_key, const uint flag); +void print_range(String *out, const KEY_PART_INFO *key_part, + KEY_MULTI_RANGE *range, uint n_key_parts); /* @@ -2208,7 +2208,7 @@ public: @param param Parameters for range analysis of this table @param trace_object The optimizer trace object the info is appended to */ - virtual void trace_basic_info(const PARAM *param, + virtual void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const= 0; }; @@ -2251,11 +2251,11 @@ public: } DBUG_RETURN(quick); } - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; -void TRP_RANGE::trace_basic_info(const PARAM *param, +void TRP_RANGE::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { DBUG_ASSERT(param->using_real_indexes); @@ -2273,10 +2273,7 @@ void TRP_RANGE::trace_basic_info(const PARAM *param, // TRP_RANGE should not be created if there are no range intervals DBUG_ASSERT(key); - String range_info; - range_info.length(0); - range_info.set_charset(system_charset_info); - append_range_all_keyparts(&trace_range, NULL, &range_info, key, key_part); + trace_ranges(&trace_range, param, key_idx, key, key_part); } @@ -2296,7 +2293,7 @@ public: struct st_ror_scan_info *cpk_scan; /* Clustered PK scan, if there is one */ bool is_covering; /* TRUE if no row retrieval phase is necessary */ double index_scan_costs; /* SUM(cost(index_scan)) */ - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; @@ -2317,11 +2314,11 @@ public: MEM_ROOT *parent_alloc); TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */ TABLE_READ_PLAN **last_ror; /* end of the above array */ - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; -void TRP_ROR_UNION::trace_basic_info(const PARAM *param, +void TRP_ROR_UNION::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { THD *thd= param->thd; @@ -2351,12 +2348,12 @@ public: TRP_RANGE **range_scans_end; /* end of the array */ /* keys whose scans are to be filtered by cpk conditions */ key_map filtered_scans; - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; -void TRP_INDEX_INTERSECT::trace_basic_info(const PARAM *param, +void TRP_INDEX_INTERSECT::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { THD *thd= param->thd; @@ -2385,11 +2382,11 @@ public: MEM_ROOT *parent_alloc); TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */ TRP_RANGE **range_scans_end; /* end of the array */ - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; -void TRP_INDEX_MERGE::trace_basic_info(const PARAM *param, +void TRP_INDEX_MERGE::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { THD *thd= param->thd; @@ -2452,12 +2449,12 @@ public: QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows, MEM_ROOT *parent_alloc); void use_index_scan() { is_index_scan= TRUE; } - void trace_basic_info(const PARAM *param, + void trace_basic_info(PARAM *param, Json_writer_object *trace_object) const; }; -void TRP_GROUP_MIN_MAX::trace_basic_info(const PARAM *param, +void TRP_GROUP_MIN_MAX::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { THD *thd= param->thd; @@ -2489,10 +2486,8 @@ void TRP_GROUP_MIN_MAX::trace_basic_info(const PARAM *param, // can have group quick without ranges if (index_tree) { - String range_info; - range_info.set_charset(system_charset_info); - append_range_all_keyparts(&trace_range, NULL, &range_info, index_tree, - key_part); + trace_ranges(&trace_range, param, param_idx, + index_tree, key_part); } } @@ -3176,6 +3171,7 @@ double records_in_column_ranges(PARAM *param, uint idx, seq.real_keyno= MAX_KEY; seq.param= param; seq.start= tree; + seq.is_ror_scan= FALSE; seq_it= seq_if.init((void *) &seq, 0, flags); @@ -3395,7 +3391,6 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) param.mem_root= &alloc; param.old_root= thd->mem_root; param.table= table; - param.is_ror_scan= FALSE; param.remove_false_where_parts= true; if (create_key_parts_for_pseudo_indexes(¶m, used_fields)) @@ -6374,7 +6369,7 @@ typedef struct st_ror_scan_info : INDEX_SCAN_INFO { } ROR_SCAN_INFO; -void TRP_ROR_INTERSECT::trace_basic_info(const PARAM *param, +void TRP_ROR_INTERSECT::trace_basic_info(PARAM *param, Json_writer_object *trace_object) const { THD *thd= param->thd; @@ -6397,20 +6392,9 @@ void TRP_ROR_INTERSECT::trace_basic_info(const PARAM *param, trace_isect_idx.add("rows", (*cur_scan)->records); Json_writer_array trace_range(thd, "ranges"); - for (const SEL_ARG *current= (*cur_scan)->sel_arg->first(); current; - current= current->next) - { - String range_info; - range_info.set_charset(system_charset_info); - for (const SEL_ARG *part= current; part; - part= part->next_key_part ? part->next_key_part : nullptr) - { - const KEY_PART_INFO *cur_key_part= key_part + part->part; - append_range(&range_info, cur_key_part, part->min_value, - part->max_value, part->min_flag | part->max_flag); - } - trace_range.add(range_info.ptr(), range_info.length()); - } + + trace_ranges(&trace_range, param, (*cur_scan)->idx, + (*cur_scan)->sel_arg, key_part); } } @@ -7363,6 +7347,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, Cost_estimate cost; double found_read_time; uint mrr_flags, buf_size; + bool is_ror_scan= FALSE; INDEX_SCAN_INFO *index_scan; uint keynr= param->real_keynr[idx]; if (key->type == SEL_ARG::MAYBE_KEY || @@ -7377,7 +7362,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, found_records= check_quick_select(param, idx, read_index_only, key, update_tbl_stats, &mrr_flags, - &buf_size, &cost); + &buf_size, &cost, &is_ror_scan); if (found_records != HA_POS_ERROR && tree->index_scans && (index_scan= (INDEX_SCAN_INFO *)alloc_root(param->mem_root, @@ -7388,9 +7373,6 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, const KEY &cur_key= param->table->key_info[keynr]; const KEY_PART_INFO *key_part= cur_key.key_part; - String range_info; - range_info.set_charset(system_charset_info); - index_scan->idx= idx; index_scan->keynr= keynr; index_scan->key_info= ¶m->table->key_info[keynr]; @@ -7401,17 +7383,16 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, *tree->index_scans_end++= index_scan; if (unlikely(thd->trace_started())) - append_range_all_keyparts(&trace_range, NULL, &range_info, key, - key_part); + trace_ranges(&trace_range, param, idx, key, key_part); trace_range.end(); - trace_idx.add("rowid_ordered", param->is_ror_scan) + trace_idx.add("rowid_ordered", is_ror_scan) .add("using_mrr", !(mrr_flags & HA_MRR_USE_DEFAULT_IMPL)) .add("index_only", read_index_only) .add("rows", found_records) .add("cost", cost.total_cost()); } - if ((found_records != HA_POS_ERROR) && param->is_ror_scan) + if ((found_records != HA_POS_ERROR) && is_ror_scan) { tree->n_ror_scans++; tree->ror_scans_map.set_bit(idx); @@ -11026,7 +11007,8 @@ void SEL_ARG::test_use_count(SEL_ARG *root) static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, SEL_ARG *tree, bool update_tbl_stats, - uint *mrr_flags, uint *bufsize, Cost_estimate *cost) + uint *mrr_flags, uint *bufsize, Cost_estimate *cost, + bool *is_ror_scan) { SEL_ARG_RANGE_SEQ seq; RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, sel_arg_range_seq_next, 0, 0}; @@ -11051,9 +11033,9 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, param->range_count=0; param->max_key_part=0; - param->is_ror_scan= TRUE; + seq.is_ror_scan= TRUE; if (file->index_flags(keynr, 0, TRUE) & HA_KEY_SCAN_NOT_ROR) - param->is_ror_scan= FALSE; + seq.is_ror_scan= FALSE; *mrr_flags= param->force_default_mrr? HA_MRR_USE_DEFAULT_IMPL: 0; /* @@ -11106,12 +11088,12 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, TODO: Don't have this logic here, make table engines return appropriate flags instead. */ - param->is_ror_scan= FALSE; + seq.is_ror_scan= FALSE; } else if (param->table->s->primary_key == keynr && pk_is_clustered) { /* Clustered PK scan is always a ROR scan (TODO: same as above) */ - param->is_ror_scan= TRUE; + seq.is_ror_scan= TRUE; } else if (param->range_count > 1) { @@ -11121,8 +11103,9 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, (1,3)" returns ROR order for all records with x=1, then ROR order for records with x=3 */ - param->is_ror_scan= FALSE; + seq.is_ror_scan= FALSE; } + *is_ror_scan= seq.is_ror_scan; DBUG_PRINT("exit", ("Records: %lu", (ulong) rows)); DBUG_RETURN(rows); //psergey-merge:todo: maintain first_null_comp. @@ -13547,21 +13530,19 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) Cost_estimate dummy_cost; uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL; uint mrr_bufsize=0; + bool is_ror_scan= FALSE; cur_quick_prefix_records= check_quick_select(param, cur_param_idx, FALSE /*don't care*/, cur_index_tree, TRUE, &mrr_flags, &mrr_bufsize, - &dummy_cost); + &dummy_cost, &is_ror_scan); if (unlikely(cur_index_tree && thd->trace_started())) { Json_writer_array trace_range(thd, "ranges"); const KEY_PART_INFO *key_part= cur_index_info->key_part; - - String range_info; - range_info.set_charset(system_charset_info); - append_range_all_keyparts(&trace_range, NULL, &range_info, - cur_index_tree, key_part); + trace_ranges(&trace_range, param, cur_param_idx, + cur_index_tree, key_part); } } cost_group_min_max(table, cur_index_info, cur_used_key_parts, @@ -15733,12 +15714,16 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose) } #endif /* !DBUG_OFF */ + static -void append_range(String *out, const KEY_PART_INFO *key_part, - const uchar *min_key, const uchar *max_key, const uint flag) +void print_range(String *out, const KEY_PART_INFO *key_part, + KEY_MULTI_RANGE *range, uint n_key_parts) { - if (out->length() > 0) - out->append(STRING_WITH_LEN(" AND ")); + uint flag= range->range_flag; + String key_name; + key_name.set_charset(system_charset_info); + key_part_map keypart_map= range->start_key.keypart_map | + range->end_key.keypart_map; if (flag & GEOM_FLAG) { @@ -15747,22 +15732,24 @@ void append_range(String *out, const KEY_PART_INFO *key_part, range types, so printing "col < some_geom" doesn't make sense. Just print the column name, not operator. */ - out->append(key_part->field->field_name); + print_keyparts_name(out, key_part, n_key_parts, keypart_map); out->append(STRING_WITH_LEN(" ")); - print_key_value(out, key_part, min_key); + print_key_value(out, key_part, range->start_key.key, + range->start_key.length); return; } if (!(flag & NO_MIN_RANGE)) { - print_key_value(out, key_part, min_key); + print_key_value(out, key_part, range->start_key.key, + range->start_key.length); if (flag & NEAR_MIN) out->append(STRING_WITH_LEN(" < ")); else out->append(STRING_WITH_LEN(" <= ")); } - out->append(key_part->field->field_name); + print_keyparts_name(out, key_part, n_key_parts, keypart_map); if (!(flag & NO_MAX_RANGE)) { @@ -15770,7 +15757,8 @@ void append_range(String *out, const KEY_PART_INFO *key_part, out->append(STRING_WITH_LEN(" < ")); else out->append(STRING_WITH_LEN(" <= ")); - print_key_value(out, key_part, max_key); + print_key_value(out, key_part, range->end_key.key, + range->end_key.length); } } @@ -15778,60 +15766,43 @@ void append_range(String *out, const KEY_PART_INFO *key_part, Add ranges to the trace For ex: - query: select * from t1 where a=2 ; - and we have an index on a , so we create a range - 2 <= a <= 2 + lets say we have an index a_b(a,b) + query: select * from t1 where a=2 and b=4 ; + so we create a range: + (2,4) <= (a,b) <= (2,4) this is added to the trace */ -static void append_range_all_keyparts(Json_writer_array *range_trace, - String *range_string, - String *range_so_far, const SEL_ARG *keypart, - const KEY_PART_INFO *key_parts) +static void trace_ranges(Json_writer_array *range_trace, + PARAM *param, uint idx, + SEL_ARG *keypart, + const KEY_PART_INFO *key_parts) { - - DBUG_ASSERT(keypart); - DBUG_ASSERT(keypart && keypart != &null_element); - - // Navigate to first interval in red-black tree + SEL_ARG_RANGE_SEQ seq; + KEY_MULTI_RANGE range; + range_seq_t seq_it; + uint flags= 0; + RANGE_SEQ_IF seq_if = {NULL, sel_arg_range_seq_init, + sel_arg_range_seq_next, 0, 0}; + KEY *keyinfo= param->table->key_info + param->real_keynr[idx]; + uint n_key_parts= param->table->actual_n_key_parts(keyinfo); + seq.keyno= idx; + seq.real_keyno= param->real_keynr[idx]; + seq.param= param; + seq.start= keypart; + /* + is_ror_scan is set to FALSE here, because we are only interested + in iterating over all the ranges and printing them. + */ + seq.is_ror_scan= FALSE; const KEY_PART_INFO *cur_key_part= key_parts + keypart->part; - const SEL_ARG *keypart_range= keypart->first(); - const size_t save_range_so_far_length= range_so_far->length(); - + seq_it= seq_if.init((void *) &seq, 0, flags); - while (keypart_range) + while (!seq_if.next(seq_it, &range)) { - // Append the current range predicate to the range String - switch (keypart->type) - { - case SEL_ARG::Type::KEY_RANGE: - append_range(range_so_far, cur_key_part, keypart_range->min_value, - keypart_range->max_value, - keypart_range->min_flag | keypart_range->max_flag); - break; - case SEL_ARG::Type::MAYBE_KEY: - range_so_far->append("MAYBE_KEY"); - break; - case SEL_ARG::Type::IMPOSSIBLE: - range_so_far->append("IMPOSSIBLE"); - break; - default: - DBUG_ASSERT(false); - break; - } - - if (keypart_range->next_key_part && - keypart_range->next_key_part->part == - keypart_range->part + 1 && - keypart_range->is_singlepoint()) - { - append_range_all_keyparts(range_trace, range_string, range_so_far, - keypart_range->next_key_part, key_parts); - } - else - range_trace->add(range_so_far->c_ptr_safe(), range_so_far->length()); - keypart_range= keypart_range->next; - range_so_far->length(save_range_so_far_length); + StringBuffer<128> range_info(system_charset_info); + print_range(&range_info, cur_key_part, &range, n_key_parts); + range_trace->add(range_info.c_ptr_safe(), range_info.length()); } } @@ -15841,70 +15812,110 @@ static void append_range_all_keyparts(Json_writer_array *range_trace, @param[out] out String the key is appended to @param[in] key_part Index components description @param[in] key Key tuple + @param[in] used_length length of the key tuple */ + static void print_key_value(String *out, const KEY_PART_INFO *key_part, - const uchar *key) + const uchar* key, uint used_length) { + out->append(STRING_WITH_LEN("(")); Field *field= key_part->field; + StringBuffer<128> tmp(system_charset_info); + TABLE *table= field->table; + uint store_length; + my_bitmap_map *old_sets[2]; + dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set); + const uchar *key_end= key+used_length; - if (field->flags & BLOB_FLAG) + for (; key < key_end; key+=store_length, key_part++) { - // Byte 0 of a nullable key is the null-byte. If set, key is NULL. - if (field->real_maybe_null() && *key) - out->append(STRING_WITH_LEN("NULL")); - else - (field->type() == MYSQL_TYPE_GEOMETRY) - ? out->append(STRING_WITH_LEN("unprintable_geometry_value")) - : out->append(STRING_WITH_LEN("unprintable_blob_value")); - return; - } + field= key_part->field; + store_length= key_part->store_length; + if (field->flags & BLOB_FLAG) + { + // Byte 0 of a nullable key is the null-byte. If set, key is NULL. + if (field->real_maybe_null() && *key) + out->append(STRING_WITH_LEN("NULL")); + else + (field->type() == MYSQL_TYPE_GEOMETRY) + ? out->append(STRING_WITH_LEN("unprintable_geometry_value")) + : out->append(STRING_WITH_LEN("unprintable_blob_value")); + goto next; + } - uint store_length= key_part->store_length; + if (field->real_maybe_null()) + { + /* + Byte 0 of key is the null-byte. If set, key is NULL. + Otherwise, print the key value starting immediately after the + null-byte + */ + if (*key) + { + out->append(STRING_WITH_LEN("NULL")); + goto next; + } + key++; // Skip null byte + store_length--; + } - if (field->real_maybe_null()) - { /* - Byte 0 of key is the null-byte. If set, key is NULL. - Otherwise, print the key value starting immediately after the - null-byte + Binary data cannot be converted to UTF8 which is what the + optimizer trace expects. If the column is binary, the hex + representation is printed to the trace instead. */ - if (*key) + if (field->flags & BINARY_FLAG) { - out->append(STRING_WITH_LEN("NULL")); - return; + out->append("0x"); + for (uint i = 0; i < store_length; i++) + { + out->append(_dig_vec_lower[*(key + i) >> 4]); + out->append(_dig_vec_lower[*(key + i) & 0x0F]); + } + goto next; } - key++; // Skip null byte - store_length--; + + field->set_key_image(key, key_part->length); + if (field->type() == MYSQL_TYPE_BIT) + (void)field->val_int_as_str(&tmp, 1); // may change tmp's charset + else + field->val_str(&tmp); // may change tmp's charset + out->append(tmp.ptr(), tmp.length(), tmp.charset()); + + next: + if (key + store_length < key_end) + out->append(STRING_WITH_LEN(",")); } + dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets); + out->append(STRING_WITH_LEN(")")); +} - /* - Binary data cannot be converted to UTF8 which is what the - optimizer trace expects. If the column is binary, the hex - representation is printed to the trace instead. - */ - if (field->flags & BINARY_FLAG) +/** + Print key parts involed in a range + @param[out] out String the key is appended to + @param[in] key_part Index components description + @param[in] n_keypart Number of keyparts in index + @param[in] keypart_map map for keyparts involved in the range +*/ + +void print_keyparts_name(String *out, const KEY_PART_INFO *key_part, + uint n_keypart, key_part_map keypart_map) +{ + uint i; + out->append(STRING_WITH_LEN("(")); + bool first_keypart= TRUE; + for (i=0; i < n_keypart; key_part++, i++) { - out->append("0x"); - for (uint i = 0; i < store_length; i++) + if (keypart_map & (1 << i)) { - out->append(_dig_vec_lower[*(key + i) >> 4]); - out->append(_dig_vec_lower[*(key + i) & 0x0F]); + if (first_keypart) + first_keypart= FALSE; + else + out->append(STRING_WITH_LEN(",")); + out->append(key_part->field->field_name); } - return; + else + break; } - - StringBuffer<128> tmp(system_charset_info); - TABLE *table= field->table; - my_bitmap_map *old_sets[2]; - - dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set); - - field->set_key_image(key, key_part->length); - if (field->type() == MYSQL_TYPE_BIT) - (void)field->val_int_as_str(&tmp, 1); // may change tmp's charset - else - field->val_str(&tmp); // may change tmp's charset - out->append(tmp.ptr(), tmp.length(), tmp.charset()); - - dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets); + out->append(STRING_WITH_LEN(")")); } |