From 009db2288ba8d22c5e8e5e047d8f8694f7097923 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 23 Sep 2022 14:48:13 +0300 Subject: [PATCH] Fixed limit optimization in range optimizer The issue was that when limit is used, SQL_SELECT::test_quick_select would set the cost of table scan to be unreasonable high to force a range to be used. The problem with this approach was that range was used even when the cost of range, when it would only read 'limit rows' would be higher than the cost of a table scan. This patch fixes it by not accepting ranges when the range can never have a lower cost than a table scan, even if every row would match the WHERE clause. --- mysql-test/main/order_by.test | 1 + sql/ha_partition.cc | 4 +- sql/ha_partition.h | 2 +- sql/handler.h | 16 ++++- sql/multi_range_read.cc | 97 ++++++++++++++++++--------- sql/multi_range_read.h | 2 +- sql/opt_range.cc | 63 +++++++++-------- storage/connect/ha_connect.cc | 5 +- storage/connect/ha_connect.h | 3 +- storage/innobase/handler/ha_innodb.cc | 6 +- storage/innobase/handler/ha_innodb.h | 1 + storage/maria/ha_maria.cc | 5 +- storage/maria/ha_maria.h | 3 +- storage/mroonga/ha_mroonga.cpp | 15 +++-- storage/mroonga/ha_mroonga.hpp | 5 +- storage/myisam/ha_myisam.cc | 5 +- storage/myisam/ha_myisam.h | 3 +- storage/spider/ha_spider.cc | 2 + storage/spider/ha_spider.h | 1 + 19 files changed, 154 insertions(+), 85 deletions(-) diff --git a/mysql-test/main/order_by.test b/mysql-test/main/order_by.test index 917f2737eec..24c90a62041 100644 --- a/mysql-test/main/order_by.test +++ b/mysql-test/main/order_by.test @@ -799,6 +799,7 @@ INSERT INTO t2 SELECT * FROM t1 ORDER BY id; EXPLAIN SELECT id,c3 FROM t2 WHERE c2=11 ORDER BY c3 LIMIT 20; EXPLAIN SELECT id,c3 FROM t2 WHERE c2=11 ORDER BY c3 LIMIT 4000; +EXPLAIN SELECT id,c3 FROM t2 WHERE c2=11 ORDER BY c3 LIMIT 6000; EXPLAIN SELECT id,c3 FROM t2 WHERE c2 BETWEEN 10 AND 12 ORDER BY c3 LIMIT 20; EXPLAIN SELECT id,c3 FROM t2 WHERE c2 BETWEEN 20 AND 30 ORDER BY c3 LIMIT 4000; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 701bffd8dd7..30c1832fadc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6575,7 +6575,7 @@ ha_rows ha_partition::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *mrr_mode, + uint *mrr_mode, ha_rows limit, Cost_estimate *cost) { int error; @@ -6636,7 +6636,7 @@ ha_rows ha_partition::multi_range_read_info_const(uint keyno, &m_partition_part_key_multi_range_hld[i], m_part_mrr_range_length[i], &m_mrr_buffer_size[i], - &tmp_mrr_mode, &part_cost); + &tmp_mrr_mode, limit, &part_cost); if (tmp_rows == HA_POS_ERROR) { m_part_spec= save_part_spec; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index febc62d9bcf..86d8cdb7cee 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -919,7 +919,7 @@ public: ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *mrr_mode, + uint *mrr_mode, ha_rows limit, Cost_estimate *cost) override; ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, diff --git a/sql/handler.h b/sql/handler.h index 98ff37cd268..9ad868a7692 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2790,6 +2790,7 @@ public: double comp_cost; /* Cost of comparing found rows with WHERE clause */ double copy_cost; /* Copying the data to 'record' */ double mem_cost; /* cost of used memory */ + double limit_cost; /* Total cost when restricting rows with limit */ static constexpr double IO_COEFF= 1; static constexpr double CPU_COEFF= 1; @@ -2853,8 +2854,8 @@ public: { avg_io_cost= 1.0; idx_avg_io_cost= 1.0; - io_count= idx_io_count= cpu_cost= idx_cpu_cost= mem_cost= import_cost= - comp_cost= copy_cost= 0.0; + io_count= idx_io_count= cpu_cost= idx_cpu_cost= mem_cost= import_cost= 0.0; + comp_cost= copy_cost= limit_cost= 0.0; } void multiply(double m) @@ -2865,6 +2866,7 @@ public: idx_cpu_cost *= m; import_cost *= m; comp_cost *= m; + limit_cost*= m; /* Don't multiply mem_cost */ } @@ -2890,6 +2892,7 @@ public: idx_cpu_cost += cost->idx_cpu_cost; import_cost += cost->import_cost; comp_cost+= cost->comp_cost; + limit_cost+= cost->limit_cost; } void add_io(double add_io_cnt, double add_avg_cost) @@ -4093,7 +4096,7 @@ public: virtual ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *mrr_mode, + uint *mrr_mode, ha_rows limit, Cost_estimate *cost); virtual ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, @@ -4102,6 +4105,13 @@ public: uint n_ranges, uint mrr_mode, HANDLER_BUFFER *buf); virtual int multi_range_read_next(range_id_t *range_info); +private: + inline void calculate_costs(Cost_estimate *cost, uint keyno, + uint ranges, uint flags, + ha_rows total_rows, + ulonglong io_blocks, + ulonglong unassigned_single_point_ranges); +public: /* Return string representation of the MRR plan. diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index d4103f669fa..e4fd1e75176 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -22,6 +22,50 @@ #include "rowid_filter.h" #include "optimizer_defaults.h" + + +/* The following calculation is the same as in multi_range_read_info() */ + +void handler::calculate_costs(Cost_estimate *cost, uint keyno, + uint n_ranges, uint flags, + ha_rows total_rows, + ulonglong io_blocks, + ulonglong unassigned_single_point_ranges) +{ + double key_cost; + cost->reset(); + cost->avg_io_cost= cost->idx_avg_io_cost= 0; // Not used! + + if (!is_clustering_key(keyno)) + { + key_cost= ha_keyread_time(keyno, n_ranges, total_rows, io_blocks); + cost->idx_cpu_cost= key_cost; + + if (!(flags & HA_MRR_INDEX_ONLY)) + { + /* ha_rnd_pos_time includes ROW_COPY_COST */ + cost->cpu_cost= ha_rnd_pos_time(total_rows); + } + else + { + /* Index only read */ + cost->copy_cost= rows2double(total_rows) * KEY_COPY_COST; + } + } + else + { + /* Clustered index */ + io_blocks+= unassigned_single_point_ranges; + key_cost= ha_keyread_time(keyno, n_ranges, total_rows, io_blocks); + cost->idx_cpu_cost= key_cost; + cost->copy_cost= rows2double(total_rows) * ROW_COPY_COST; + } + cost->comp_cost= (rows2double(total_rows) * WHERE_COST + + MULTI_RANGE_READ_SETUP_COST); +} + + + /**************************************************************************** * Default MRR implementation (MRR to non-MRR converter) ***************************************************************************/ @@ -57,10 +101,12 @@ contain scan parameters. */ + ha_rows handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges_arg, uint *bufsz, uint *flags, + ha_rows top_limit, Cost_estimate *cost) { KEY_MULTI_RANGE range; @@ -303,40 +349,22 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, if (total_rows != HA_POS_ERROR) { - double key_cost; set_if_smaller(total_rows, max_rows); - - /* The following calculation is the same as in multi_range_read_info(): */ *flags |= HA_MRR_USE_DEFAULT_IMPL; - cost->reset(); - cost->avg_io_cost= cost->idx_avg_io_cost= 0; // Not used! - - if (!is_clustering_key(keyno)) + calculate_costs(cost, keyno, n_ranges, *flags, total_rows, + io_blocks, unassigned_single_point_ranges); + if (top_limit < total_rows) { - key_cost= ha_keyread_time(keyno, n_ranges, total_rows, io_blocks); - cost->idx_cpu_cost= key_cost; - - if (!(*flags & HA_MRR_INDEX_ONLY)) - { - /* ha_rnd_pos_time includes ROW_COPY_COST */ - cost->cpu_cost= ha_rnd_pos_time(total_rows); - } - else - { - /* Index only read */ - cost->copy_cost= rows2double(total_rows) * KEY_COPY_COST; - } + /* + Calculate what the cost would be if we only have to read 'top_limit' + rows. This is the lowest possible cost fwhen using the range + when we find the 'accepted rows' at once. + */ + Cost_estimate limit_cost; + calculate_costs(&limit_cost, keyno, n_ranges, *flags, top_limit, + io_blocks, unassigned_single_point_ranges); + cost->limit_cost= limit_cost.total_cost(); } - else - { - /* Clustered index */ - io_blocks+= unassigned_single_point_ranges; - key_cost= ha_keyread_time(keyno, n_ranges, total_rows, io_blocks); - cost->idx_cpu_cost= key_cost; - cost->copy_cost= rows2double(total_rows) * ROW_COPY_COST; - } - cost->comp_cost= (rows2double(total_rows) * WHERE_COST + - MULTI_RANGE_READ_SETUP_COST); } DBUG_PRINT("statistics", ("key: %s rows: %llu total_cost: %.3f io_blocks: %llu " @@ -1717,8 +1745,9 @@ ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows, */ ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, - void *seq_init_param, uint n_ranges, - uint *bufsz, uint *flags, Cost_estimate *cost) + void *seq_init_param, uint n_ranges, + uint *bufsz, uint *flags, ha_rows limit, + Cost_estimate *cost) { ha_rows rows; uint def_flags= *flags; @@ -1728,7 +1757,9 @@ ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, seq_init_param, n_ranges, &def_bufsz, - &def_flags, cost); + &def_flags, + limit, + cost); if (rows == HA_POS_ERROR) { /* Default implementation can't perform MRR scan => we can't either */ diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h index 37a00e3086f..76b026f994a 100644 --- a/sql/multi_range_read.h +++ b/sql/multi_range_read.h @@ -576,7 +576,7 @@ public: ha_rows dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost); + uint *flags, ha_rows limit, Cost_estimate *cost); int dsmrr_explain_info(uint mrr_mode, char *str, size_t size); private: diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9224f1d03f2..78e577c31f2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -345,7 +345,8 @@ struct st_index_scan_info; struct st_ror_scan_info; 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, +static ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit, + bool index_only, SEL_ARG *tree, bool update_tbl_stats, uint *mrr_flags, uint *bufsize, Cost_estimate *cost, bool *is_ror_scan); @@ -356,7 +357,8 @@ QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, bool index_read_must_be_used, bool for_range_access, - double read_time); + double read_time, ha_rows limit, + bool using_table_scan); static TRP_INDEX_INTERSECT *get_best_index_intersect(PARAM *param, SEL_TREE *tree, double read_time); @@ -370,7 +372,9 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, double read_time); static TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, - double read_time, bool named_trace= false); + double read_time, ha_rows limit, + bool named_trace, + bool using_table_scan); static TABLE_READ_PLAN *merge_same_index_scans(PARAM *param, SEL_IMERGE *imerge, TRP_INDEX_MERGE *imerge_trp, @@ -2715,21 +2719,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, else { read_time= head->file->ha_scan_and_compare_time(records); - - /* - Force the detection of range access if LIMIT is used. - The idea is that we want to store all possible range - accesses to see if we can use them to resolve an ORDER BY. - Ranges with too high costs will be pruned in best_access_path(). - - The test for read_time is there only to not modify read_time if - ha_scan_and_compare_time() returned a really big value - */ - if (limit < records && read_time < (double) records * 2) - { - read_time= (double) records * 2; // Force to use index + if (limit < records) notnull_cond= NULL; - } } possible_keys.clear_all(); @@ -2959,7 +2950,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, /* Get best 'range' plan and prepare data for making other plans */ if ((range_trp= get_key_scans_params(¶m, tree, only_single_index_range_scan, - true, best_read_time))) + true, best_read_time, limit, + 1))) { best_trp= range_trp; best_read_time= best_trp->read_cost; @@ -3025,7 +3017,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, Json_writer_array trace_idx_merge(thd, "analyzing_index_merge_union"); while ((imerge= it++)) { - new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time); + new_conj_trp= get_best_disjunct_quick(¶m, imerge, best_read_time, + limit, 0, 1); if (new_conj_trp) param.table->set_opt_range_condition_rows(new_conj_trp->records); if (new_conj_trp && @@ -5210,7 +5203,9 @@ static double get_sweep_read_cost(const PARAM *param, ha_rows records, static TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, - double read_time, bool named_trace) + double read_time, ha_rows limit, + bool named_trace, + bool using_table_scan) { SEL_TREE **ptree; TRP_INDEX_MERGE *imerge_trp= NULL; @@ -5274,7 +5269,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, "tree in SEL_IMERGE");); Json_writer_object trace_idx(thd); if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, FALSE, - read_time))) + read_time, limit, using_table_scan))) { /* One of index scans in this index_merge is more expensive than entire @@ -5624,7 +5619,8 @@ TABLE_READ_PLAN *merge_same_index_scans(PARAM *param, SEL_IMERGE *imerge, DBUG_ASSERT(imerge->trees_next>imerge->trees); if (imerge->trees_next-imerge->trees > 1) - trp= get_best_disjunct_quick(param, imerge, read_time, true); + trp= get_best_disjunct_quick(param, imerge, read_time, HA_POS_ERROR, true, + 0); else { /* @@ -7594,7 +7590,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, bool index_read_must_be_used, bool for_range_access, - double read_time) + double read_time, ha_rows limit, + bool using_table_scan) { uint idx, UNINIT_VAR(best_idx); SEL_ARG *key_to_read= NULL; @@ -7646,7 +7643,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, Json_writer_object trace_idx(thd); trace_idx.add("index", param->table->key_info[keynr].name); - found_records= check_quick_select(param, idx, read_index_only, key, + found_records= check_quick_select(param, idx, limit, read_index_only, key, for_range_access, &mrr_flags, &buf_size, &cost, &is_ror_scan); @@ -7680,19 +7677,29 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, trace_range.end(); if (unlikely(trace_idx.trace_started())) + { 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", found_read_time); + if (using_table_scan && cost.limit_cost != 0.0) + trace_idx.add("cost_with_limit", cost.limit_cost); + } } if (is_ror_scan) { tree->n_ror_scans++; tree->ror_scans_map.set_bit(idx); } - if (read_time > found_read_time) + /* + Use range if best range so far or if we are comparing to a table scan + and the cost with limit approximation is better than the table scan + */ + if (read_time > found_read_time || + (using_table_scan && cost.limit_cost != 0.0 && + read_time > cost.limit_cost)) { read_time= found_read_time; best_records= found_records; @@ -7700,6 +7707,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, best_idx= idx; best_mrr_flags= mrr_flags; best_buf_size= buf_size; + using_table_scan= 0; trace_idx.add("chosen", true); } else if (unlikely(trace_idx.trace_started())) @@ -11703,7 +11711,8 @@ static bool check_if_first_key_part_has_only_one_value(SEL_ARG *arg) */ static -ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, +ha_rows check_quick_select(PARAM *param, uint idx, ha_rows limit, + bool index_only, SEL_ARG *tree, bool update_tbl_stats, uint *mrr_flags, uint *bufsize, Cost_estimate *cost, bool *is_ror_scan) @@ -11765,7 +11774,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, */ if (param->table->pos_in_table_list->is_non_derived()) rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, - bufsize, mrr_flags, cost); + bufsize, mrr_flags, limit, cost); param->quick_rows[keynr]= rows; if (rows != HA_POS_ERROR) { diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 23d3c7c1058..73dfa0af1a9 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -7400,7 +7400,8 @@ int ha_connect::multi_range_read_next(range_id_t *range_info) ha_rows ha_connect::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost) + uint *flags, ha_rows limit, + Cost_estimate *cost) { /* This call is here because there is no location where this->table would @@ -7414,7 +7415,7 @@ ha_rows ha_connect::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, *flags|= HA_MRR_USE_DEFAULT_IMPL; ha_rows rows= ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, - bufsz, flags, cost); + bufsz, flags, limit, cost); xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL); return rows; } // end of multi_range_read_info_const diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index ca3b69bb552..a5b139a5689 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -502,7 +502,8 @@ int index_prev(uchar *buf); ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost); + uint *flags, ha_rows limit, + Cost_estimate *cost); ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *flags, Cost_estimate *cost); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d7ea13f8568..fc20003c7f5 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19972,6 +19972,7 @@ ha_innobase::multi_range_read_info_const( uint n_ranges, uint* bufsz, uint* flags, + ha_rows limit, Cost_estimate* cost) { /* See comments in ha_myisam::multi_range_read_info_const */ @@ -19981,8 +19982,9 @@ ha_innobase::multi_range_read_info_const( *flags |= HA_MRR_USE_DEFAULT_IMPL; } - ha_rows res= m_ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, - bufsz, flags, cost); + ha_rows res= m_ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, + n_ranges, + bufsz, flags, limit, cost); return res; } diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 92d6dcb9afb..60b56b4a22f 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -383,6 +383,7 @@ public: uint n_ranges, uint* bufsz, uint* flags, + ha_rows limit, Cost_estimate* cost) override; /** Initialize multi range read and get information. diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index e9230d1944f..f8b72bf85d3 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -4208,7 +4208,8 @@ int ha_maria::multi_range_read_next(range_id_t *range_info) ha_rows ha_maria::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost) + uint *flags, ha_rows limit, + Cost_estimate *cost) { /* This call is here because there is no location where this->table would @@ -4217,7 +4218,7 @@ ha_rows ha_maria::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, */ ds_mrr.init(this, table); return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, - flags, cost); + flags, limit, cost); } ha_rows ha_maria::multi_range_read_info(uint keyno, uint n_ranges, uint keys, diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h index 38919d5c542..1486c2d7904 100644 --- a/storage/maria/ha_maria.h +++ b/storage/maria/ha_maria.h @@ -175,7 +175,8 @@ public: ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost) override final; + uint *flags, ha_rows limit, + Cost_estimate *cost) override final; ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *flags, Cost_estimate *cost) override final; diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 2d8f372e6df..85d6473ded3 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -12314,6 +12314,7 @@ ha_rows ha_mroonga::wrapper_multi_range_read_info_const(uint keyno, uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost) { MRN_DBUG_ENTER_METHOD(); @@ -12321,7 +12322,8 @@ ha_rows ha_mroonga::wrapper_multi_range_read_info_const(uint keyno, KEY *key_info = &(table->key_info[keyno]); if (mrn_is_geo_key(key_info)) { rows = handler::multi_range_read_info_const(keyno, seq, seq_init_param, - n_ranges, bufsz, flags, cost); + n_ranges, bufsz, flags, limit, + cost); DBUG_RETURN(rows); } MRN_SET_WRAP_SHARE_KEY(share, table->s); @@ -12330,7 +12332,7 @@ ha_rows ha_mroonga::wrapper_multi_range_read_info_const(uint keyno, set_pk_bitmap(); rows = wrap_handler->multi_range_read_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, flags, - cost); + limit, cost); MRN_SET_BASE_SHARE_KEY(share, table->s); MRN_SET_BASE_TABLE_KEY(this, table); DBUG_RETURN(rows); @@ -12342,20 +12344,21 @@ ha_rows ha_mroonga::storage_multi_range_read_info_const(uint keyno, uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost) { MRN_DBUG_ENTER_METHOD(); ha_rows rows = handler::multi_range_read_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, flags, - cost); + limit, cost); DBUG_RETURN(rows); } ha_rows ha_mroonga::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, + uint *flags, ha_rows limit, Cost_estimate *cost) { MRN_DBUG_ENTER_METHOD(); @@ -12364,11 +12367,11 @@ ha_rows ha_mroonga::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, { rows = wrapper_multi_range_read_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, - flags, cost); + flags, limit, cost); } else { rows = storage_multi_range_read_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, - flags, cost); + flags, limit, cost); } DBUG_RETURN(rows); } diff --git a/storage/mroonga/ha_mroonga.hpp b/storage/mroonga/ha_mroonga.hpp index 827714f5edb..27219ffd158 100644 --- a/storage/mroonga/ha_mroonga.hpp +++ b/storage/mroonga/ha_mroonga.hpp @@ -505,7 +505,8 @@ public: ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost) mrn_override; + uint *flags, ha_rows limit, + Cost_estimate *cost) mrn_override; ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS uint key_parts, @@ -1057,6 +1058,7 @@ private: uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost); ha_rows storage_multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, @@ -1064,6 +1066,7 @@ private: uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost); ha_rows wrapper_multi_range_read_info(uint keyno, uint n_ranges, uint keys, #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index bbae99ce2d3..df47bda9c86 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -2663,7 +2663,8 @@ int ha_myisam::multi_range_read_next(range_id_t *range_info) ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost) + uint *flags, ha_rows limit, + Cost_estimate *cost) { /* This call is here because there is no location where this->table would @@ -2672,7 +2673,7 @@ ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, */ ds_mrr.init(this, table); return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz, - flags, cost); + flags, limit, cost); } ha_rows ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys, diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 55ce19494d9..d6ae007a446 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -165,7 +165,8 @@ public: ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, void *seq_init_param, uint n_ranges, uint *bufsz, - uint *flags, Cost_estimate *cost); + uint *flags, ha_rows limit, + Cost_estimate *cost) override; ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys, uint key_parts, uint *bufsz, uint *flags, Cost_estimate *cost); diff --git a/storage/spider/ha_spider.cc b/storage/spider/ha_spider.cc index 1bb4ec26fa2..5cf67a091db 100644 --- a/storage/spider/ha_spider.cc +++ b/storage/spider/ha_spider.cc @@ -3151,6 +3151,7 @@ ha_rows ha_spider::multi_range_read_info_const( uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost ) { @@ -3190,6 +3191,7 @@ ha_rows ha_spider::multi_range_read_info_const( n_ranges, bufsz, flags, + limit, cost ); *flags &= ~HA_MRR_USE_DEFAULT_IMPL; diff --git a/storage/spider/ha_spider.h b/storage/spider/ha_spider.h index 348f5a0ee06..ac865e78f2c 100644 --- a/storage/spider/ha_spider.h +++ b/storage/spider/ha_spider.h @@ -250,6 +250,7 @@ public: uint n_ranges, uint *bufsz, uint *flags, + ha_rows limit, Cost_estimate *cost ); ha_rows multi_range_read_info(