From 7c57c0e92347f86282f93974d8cb127898fa1b5c Mon Sep 17 00:00:00 2001 From: yuanyazhi Date: Tue, 3 Dec 2024 20:06:49 +0800 Subject: [PATCH] fix calc union index cost --- mysql-test/suite/ctc/r/ctc_dml_ignore.result | 62 ++++++++++++++++++++ mysql-test/suite/ctc/t/ctc_dml_ignore.test | 16 +++++ storage/ctc/ctc_cbo.cc | 22 +++++-- storage/ctc/ctc_cbo.h | 5 +- 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/ctc/r/ctc_dml_ignore.result b/mysql-test/suite/ctc/r/ctc_dml_ignore.result index 03867bb..3f8f3da 100644 --- a/mysql-test/suite/ctc/r/ctc_dml_ignore.result +++ b/mysql-test/suite/ctc/r/ctc_dml_ignore.result @@ -468,6 +468,68 @@ count(*) 3 drop table t1; drop table t2; +CREATE TABLE `test` ( +`a` int NOT NULL, +`b` int NOT NULL, +KEY `idx_union` (`a`,`b`) +); +insert into test values(2, 2), (3, 3), (4, 4), (5, 5); +analyze table test; +Table Op Msg_type Msg_text +test.test analyze status OK +explain format = json select * from test where a >= 1 and a <= 8 and b = 2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost_info": { + "query_cost": "0.65" + }, + "table": { + "table_name": "test", + "access_type": "index", + "possible_keys": [ + "idx_union" + ], + "key": "idx_union", + "used_key_parts": [ + "a", + "b" + ], + "key_length": "8", + "rows_examined_per_scan": 4, + "rows_produced_per_join": 1, + "filtered": "25.00", + "pushed_condition": "((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8))", + "using_index": true, + "cost_info": { + "read_cost": "0.55", + "eval_cost": "0.10", + "prefix_cost": "0.65", + "data_read_per_join": "16" + }, + "used_columns": [ + "a", + "b" + ], + "attached_condition": "((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8))" + } + } +} +Warnings: +Note 1003 /* select#1 */ select `test`.`test`.`a` AS `a`,`test`.`test`.`b` AS `b` from `test`.`test` where ((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8)) +drop table test; +create table t1(a int(10), key(a)); +Warnings: +Warning 1681 Integer display width is deprecated and will be removed in a future release. +insert into t1 values(1), (2), (1), (1), (2), (1); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select count(distinct a) from t1; +count(distinct a) +2 +drop table t1; create database db_trigger; use db_trigger; SET @old_sql_mode := @@sql_mode ; diff --git a/mysql-test/suite/ctc/t/ctc_dml_ignore.test b/mysql-test/suite/ctc/t/ctc_dml_ignore.test index ad89b1a..57c833f 100644 --- a/mysql-test/suite/ctc/t/ctc_dml_ignore.test +++ b/mysql-test/suite/ctc/t/ctc_dml_ignore.test @@ -221,6 +221,22 @@ select /*+ INDEX_MERGE(t2 idx_char_col,idx_enum_col) */ count(*) from t2 where e drop table t1; drop table t2; +CREATE TABLE `test` ( + `a` int NOT NULL, + `b` int NOT NULL, + KEY `idx_union` (`a`,`b`) +); +insert into test values(2, 2), (3, 3), (4, 4), (5, 5); +analyze table test; +explain format = json select * from test where a >= 1 and a <= 8 and b = 2; +drop table test; + +create table t1(a int(10), key(a)); +insert into t1 values(1), (2), (1), (1), (2), (1); +analyze table t1; +select count(distinct a) from t1; +drop table t1; + create database db_trigger; use db_trigger; SET @old_sql_mode := @@sql_mode ; diff --git a/storage/ctc/ctc_cbo.cc b/storage/ctc/ctc_cbo.cc index d9ec830..5f45fa3 100644 --- a/storage/ctc/ctc_cbo.cc +++ b/storage/ctc/ctc_cbo.cc @@ -578,7 +578,7 @@ static double calc_hist_between_density(ctc_cbo_stats_table_t *cbo_stats, } double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_index_part, ctc_range_key *key, - uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs) + uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs, bool *continue_calc) { double density = DEFAULT_RANGE_DENSITY; ctc_key *min_key = key->min_key; @@ -601,11 +601,17 @@ double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_ } extract_boundary_value(min_key, &cur_index_part, &min_key_val, low_val, key_offset); extract_boundary_value(max_key, &cur_index_part, &max_key_val, high_val, key_offset); + + en_ctc_compare_type comapare_value = compare(&max_key_val, &min_key_val, cur_index_part.field, cs); + if (comapare_value != EQUAL) { + // 联合索引上下界不同时,当前列为范围查询,下一列开始不符合联合索引的最左匹配原则,无需继续计算 + *continue_calc = false; + } if (compare(&max_key_val, low_val, cur_index_part.field, cs) == LESS || compare(&min_key_val, high_val, cur_index_part.field, cs) == GREAT) { return 0; } - en_ctc_compare_type comapare_value = compare(&max_key_val, &min_key_val, cur_index_part.field, cs); + if (comapare_value == EQUAL && min_key->cmp_type == CMP_TYPE_CLOSE_INTERNAL && max_key->cmp_type == CMP_TYPE_CLOSE_INTERNAL) { return calc_hist_equal_density(cbo_stats, &max_key_val, col_id, cur_index_part.field, cs); @@ -633,7 +639,8 @@ void calc_accumulate_gcol_num(uint num_fields, Field** field, uint32_t *acc_gcol } double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_key* key, KEY_PART_INFO *cur_index_part, - uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs) + uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs, + bool *continue_calc) { double col_selectivity = 0.0; @@ -648,7 +655,8 @@ double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_ /*when the col of min_key and max_key both have null-val --> select * from table where col is null*/ col_selectivity = calc_equal_null_density(cbo_stats, ctc_col_id); } else { - col_selectivity = calc_density_by_cond(cbo_stats, *cur_index_part, key, key_offset, ctc_col_id, cs); + col_selectivity = calc_density_by_cond(cbo_stats, *cur_index_part, key, key_offset, + ctc_col_id, cs, continue_calc); } return col_selectivity; @@ -704,7 +712,8 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, * For all columns in used index, * density = 1.0 / (column[0]->num_distinct * ... * column[n]->num_distinct) */ - for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts; idx_col_num++) { + bool continue_calc = true; + for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts && continue_calc; idx_col_num++) { double col_selectivity = 0.0; if ((valid_map & ((uint64_t)1 << idx_col_num)) == 0) { break; @@ -723,7 +732,8 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, set_key_boundary_types(key, idx_col_num, min_key_cmp_type, max_key_cmp_type); col_selectivity = calculate_column_selectivity(cbo_stats, key, &cur_index_part, ctc_col_id, - key_offset, null_offset, table.field[mysql_col_id]->charset()); + key_offset, null_offset, table.field[mysql_col_id]->charset(), + &continue_calc); col_selectivity = eval_density_result(col_selectivity); key_offset += (varchar_offset + null_offset + cur_index_part.field->key_length()); diff --git a/storage/ctc/ctc_cbo.h b/storage/ctc/ctc_cbo.h index 1cccb4d..3bc9688 100644 --- a/storage/ctc/ctc_cbo.h +++ b/storage/ctc/ctc_cbo.h @@ -75,10 +75,11 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, void calc_accumulate_gcol_num(uint num_fields, Field** field, uint32_t *acc_gcol_num); void ctc_index_stats_update(TABLE *table, ctc_cbo_stats_t *cbo_stats); double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_index_part, ctc_range_key *key, - uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs); + uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs, bool *continue_calc); void set_key_boundary_types(ctc_range_key *key, uint32_t id, ctc_cmp_type_t min_key_cmp_type, ctc_cmp_type_t max_key_cmp_type); double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_key* key, KEY_PART_INFO *cur_index_part, - uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs); + uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs, + bool *continue_calc); void extract_boundary_value(ctc_key *rKey, KEY_PART_INFO *cur_index_part, cache_variant_t *ret_val, cache_variant_t * value, uint32_t key_offset); bool handle_null_and_single_boundary(ctc_key *rKey, Field *field, cache_variant_t *ret_val, -- Gitee