diff --git a/mysql-test/enableCases.list b/mysql-test/enableCases.list index c6fe92b73c58a189358b52235307c013b81a687e..870404c956a790159a204270d8b8656162ce2593 100644 --- a/mysql-test/enableCases.list +++ b/mysql-test/enableCases.list @@ -21,6 +21,7 @@ ctc_enum_analyze ctc_bit_analyze ctc_string_analyze ctc_dml_estimate_rows +ctc_index_cardinality # ------ END TEST CASES OF DML ------ # ------ BEGIN TEST CASES OF TRANSACTION ------ diff --git a/mysql-test/suite/ctc/r/ctc_index_cardinality.result b/mysql-test/suite/ctc/r/ctc_index_cardinality.result new file mode 100644 index 0000000000000000000000000000000000000000..2194215014be1bfcbb733abd4ab9593ebff05d36 --- /dev/null +++ b/mysql-test/suite/ctc/r/ctc_index_cardinality.result @@ -0,0 +1,102 @@ +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1; +DROP TABLE IF EXISTS db1.t1; +Warnings: +Note 1051 Unknown table 'db1.t1' +CREATE TABLE db1.t1(a INT, b INT, c INT, d INT); +INSERT INTO db1.t1 VALUES(1,1,1,1),(1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 1 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 2 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 3 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 4 NULL NULL YES BTREE YES NULL +CREATE INDEX idx_a ON db1.t1 (a); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 1 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 2 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 3 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 4 NULL NULL YES BTREE YES NULL +t1 1 idx_a 1 a A 1 NULL NULL YES BTREE YES NULL +DROP TABLE IF EXISTS db1.t1; +CREATE TABLE db1.t1 ( +a INT, +b INT, +c INT, +d INT +) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30), +PARTITION p3 VALUES LESS THAN (40) +); +INSERT INTO db1.t1 VALUES(1,1,1,1),(11,1,1,2), (21,2,2,3), (31,2,3,4), +(1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 4 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 5 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 6 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 7 NULL NULL YES BTREE YES NULL +CREATE INDEX idx_a ON db1.t1 (a); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 4 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 5 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 6 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 7 NULL NULL YES BTREE YES NULL +t1 1 idx_a 1 a A 4 NULL NULL YES BTREE YES NULL +DROP TABLE IF EXISTS db1.t1; +CREATE TABLE db1.t1 ( +a INT, +b INT, +c INT, +d INT +) +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) SUBPARTITIONS 4 ( +PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (20), +PARTITION p2 VALUES LESS THAN (30), +PARTITION p3 VALUES LESS THAN (40) +); +INSERT INTO db1.t1 VALUES(1,1,1,1),(11,1,1,2), (21,2,2,3), (31,2,3,4), +(1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 4 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 5 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 6 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 7 NULL NULL YES BTREE YES NULL +CREATE INDEX idx_a ON db1.t1 (a); +ANALYZE TABLE db1.t1; +Table Op Msg_type Msg_text +db1.t1 analyze status OK +SHOW INDEX FROM db1.t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression +t1 1 idx_abcd 1 a A 4 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 2 b A 5 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 3 c A 6 NULL NULL YES BTREE YES NULL +t1 1 idx_abcd 4 d A 7 NULL NULL YES BTREE YES NULL +t1 1 idx_a 1 a A 4 NULL NULL YES BTREE YES NULL +DROP DATABASE IF EXISTS db1; diff --git a/mysql-test/suite/ctc/t/ctc_index_cardinality.test b/mysql-test/suite/ctc/t/ctc_index_cardinality.test new file mode 100644 index 0000000000000000000000000000000000000000..c8cf6b09eba85fad5af59f89e19ca2c8318bc05c --- /dev/null +++ b/mysql-test/suite/ctc/t/ctc_index_cardinality.test @@ -0,0 +1,66 @@ +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +CREATE DATABASE db1; + +# normal table + +DROP TABLE IF EXISTS db1.t1; +CREATE TABLE db1.t1(a INT, b INT, c INT, d INT); +INSERT INTO db1.t1 VALUES(1,1,1,1),(1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d);# Compound index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; +CREATE INDEX idx_a ON db1.t1 (a); # normal index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; + +# part table +DROP TABLE IF EXISTS db1.t1; +CREATE TABLE db1.t1 ( + a INT, + b INT, + c INT, + d INT +) +PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30), + PARTITION p3 VALUES LESS THAN (40) +); +INSERT INTO db1.t1 VALUES(1,1,1,1),(11,1,1,2), (21,2,2,3), (31,2,3,4), + (1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d);# Compound index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; +CREATE INDEX idx_a ON db1.t1 (a); # normal index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; + +#sub_part table +DROP TABLE IF EXISTS db1.t1; +CREATE TABLE db1.t1 ( + a INT, + b INT, + c INT, + d INT +) +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) SUBPARTITIONS 4 ( + PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (20), + PARTITION p2 VALUES LESS THAN (30), + PARTITION p3 VALUES LESS THAN (40) +); +INSERT INTO db1.t1 VALUES(1,1,1,1),(11,1,1,2), (21,2,2,3), (31,2,3,4), + (1,1,1,2), (1,2,2,3), (1,2,3,4); +CREATE INDEX idx_abcd ON db1.t1 (a, b, c, d);# Compound index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; +CREATE INDEX idx_a ON db1.t1 (a); # normal index +ANALYZE TABLE db1.t1; +SHOW INDEX FROM db1.t1; + +DROP DATABASE IF EXISTS db1; diff --git a/storage/ctc/ctc_cbo.cc b/storage/ctc/ctc_cbo.cc index 29a30547969028a5a471d816cb431207579a944b..89f7593326e870ec56fc8eda0b6c9d7f39c1337f 100644 --- a/storage/ctc/ctc_cbo.cc +++ b/storage/ctc/ctc_cbo.cc @@ -795,13 +795,23 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, return density; } +static inline bool check_index_is_contain_null(ctc_cbo_stats_t *cbo_stats, uint32_t fld_idx) +{ + uint32_t table_part_num = cbo_stats->part_cnt == 0 ? PART_NUM_OF_NORMAL_TABLE : cbo_stats->part_cnt; + for (uint32 k = 0; k < table_part_num; k++) { + if (cbo_stats->ctc_cbo_stats_table[k].columns[fld_idx].num_null) { + return true; + } + } + return false; +} + void ctc_index_stats_update(TABLE *table, ctc_cbo_stats_t *cbo_stats) { rec_per_key_t rec_per_key = 0.0f; KEY sk; uint32_t *n_diff = cbo_stats->ndv_keys; - uint32_t records; - uint32_t table_part_num = cbo_stats->part_cnt == 0 ? 1 : cbo_stats->part_cnt; + uint32_t records = cbo_stats->records; uint32_t acc_gcol_num[CTC_MAX_COLUMNS] = {0}; calc_accumulate_gcol_num(table->s->fields, table->s->field, acc_gcol_num); if (cbo_stats->records == 0) { @@ -811,28 +821,16 @@ void ctc_index_stats_update(TABLE *table, ctc_cbo_stats_t *cbo_stats) for (uint32 i = 0; i < table->s->keys; i++) { sk = table->key_info[i]; for (uint32 j = 0; j < sk.actual_key_parts; j++) { - bool all_n_diff_is_zero = true; rec_per_key = 0.0f; uint32 fld_idx = sk.key_part[j].field->field_index(); fld_idx = fld_idx - acc_gcol_num[fld_idx]; - for (uint32 k = 0; k < table_part_num; k++) { - records = cbo_stats->ctc_cbo_stats_table[k].estimate_rows; - uint32 has_null = cbo_stats->ctc_cbo_stats_table[k].columns[fld_idx].num_null ? 1 : 0; - uint32 n_diff_part = *(n_diff + i * MAX_KEY_COLUMNS + j); - do { - if (!n_diff_part) { - break; - } - rec_per_key += static_cast(records) / static_cast(n_diff_part + has_null); - all_n_diff_is_zero = false; - } while(0); - } - - // if all n_diff(s) values 0, take records itself as rec_per_key - if (all_n_diff_is_zero) { - for (uint32 k = 0; k < table_part_num; k++) { - rec_per_key += static_cast(cbo_stats->ctc_cbo_stats_table[k].estimate_rows); - } + uint32 has_null = check_index_is_contain_null(cbo_stats, fld_idx) ? 1 : 0; + uint32 n_diff_part = *(n_diff + i * MAX_KEY_COLUMNS + j); + if (n_diff_part) { + rec_per_key = static_cast(records) / static_cast(n_diff_part + has_null); + } else { + // if all n_diff(s) values 0, take records itself as rec_per_key + rec_per_key = static_cast(records); } if (rec_per_key < 1.0) { diff --git a/storage/ctc/ctc_cbo.h b/storage/ctc/ctc_cbo.h index 3bc9688d1f9d9fe0d731ddf79b9cb240591e2d7f..2ea06201d8bd412b85ee079a7fd37539fb4582b9 100644 --- a/storage/ctc/ctc_cbo.h +++ b/storage/ctc/ctc_cbo.h @@ -24,6 +24,7 @@ #include "srv_mq_msg.h" #define REAL_EPSINON 0.00001 +#define PART_NUM_OF_NORMAL_TABLE 1 typedef enum en_ctc_compare_type { GREAT = 0, diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index 7a19d97a052b3c13c3a3b97a6960f05846208791..c2faf7f7b5da9c666320bc2e0749ba9fa66f0141 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -5437,6 +5437,8 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } + memset(m_share->cbo_stats->ctc_cbo_stats_table, 0, sizeof(ctc_cbo_stats_table_t)); + m_share->cbo_stats->ctc_cbo_stats_table->columns = (ctc_cbo_stats_column_t*)my_malloc(PSI_NOT_INSTRUMENTED, table->s->fields * sizeof(ctc_cbo_stats_column_t), MYF(MY_WME)); if (m_share->cbo_stats->ctc_cbo_stats_table->columns == nullptr) { @@ -5444,10 +5446,8 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } - for (uint col_id = 0; col_id < table->s->fields; col_id++) { - m_share->cbo_stats->ctc_cbo_stats_table->columns[col_id].hist_count = 0; - } - + memset(m_share->cbo_stats->ctc_cbo_stats_table->columns, 0, table->s->fields * sizeof(ctc_cbo_stats_column_t)); + ct_errno_t ret = (ct_errno_t)alloc_str_mysql_mem(m_share->cbo_stats, 1, table); if (ret != CT_SUCCESS) { ctc_log_error("m_share:ctc alloc str mysql mem failed, ret:%d", ret); @@ -5460,6 +5460,7 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } + memset(m_share->cbo_stats->ndv_keys, 0, table->s->keys * sizeof(uint32_t) * MAX_KEY_COLUMNS); m_share->cbo_stats->msg_len = table->s->fields * sizeof(ctc_cbo_stats_column_t); m_share->cbo_stats->key_len = table->s->keys * sizeof(uint32_t) * MAX_KEY_COLUMNS; diff --git a/storage/ctc/ha_ctcpart.cc b/storage/ctc/ha_ctcpart.cc index e05ff7b37ffa8de2de6308fc6fe70c661e416f1e..0db2188f254ede51cc9ed63b19c07220b4a7125b 100644 --- a/storage/ctc/ha_ctcpart.cc +++ b/storage/ctc/ha_ctcpart.cc @@ -1047,23 +1047,25 @@ int ha_ctcpart::initialize_cbo_stats() { ctc_log_error("alloc mem failed, m_part_share->cbo_stats->ctc_cbo_stats_table size(%lu)", part_num * sizeof(ctc_cbo_stats_table_t)); return ERR_ALLOC_MEMORY; } + memset(m_part_share->cbo_stats->ctc_cbo_stats_table, 0, part_num * sizeof(ctc_cbo_stats_table_t)); + m_part_share->cbo_stats->ndv_keys = (uint32_t*)my_malloc(PSI_NOT_INSTRUMENTED, table->s->keys * sizeof(uint32_t) * MAX_KEY_COLUMNS, MYF(MY_WME)); if (m_part_share->cbo_stats->ndv_keys == nullptr) { ctc_log_error("alloc mem failed, m_part_share->cbo_stats->ndv_keys size(%lu)", table->s->keys * sizeof(uint32_t) * MAX_KEY_COLUMNS); return ERR_ALLOC_MEMORY; } + memset(m_part_share->cbo_stats->ndv_keys, 0, table->s->keys * sizeof(uint32_t) * MAX_KEY_COLUMNS); + for (uint i = 0; i < part_num; i++) { m_part_share->cbo_stats->ctc_cbo_stats_table[i].estimate_rows = 0; m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns = (ctc_cbo_stats_column_t*)my_malloc(PSI_NOT_INSTRUMENTED, table->s->fields * sizeof(ctc_cbo_stats_column_t), MYF(MY_WME)); if (m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns == nullptr) { - ctc_log_error("alloc mem failed, m_part_share->cbo_stats->ctc_cbo_stats_table size(%lu)", table->s->fields * sizeof(ctc_cbo_stats_column_t)); - return ERR_ALLOC_MEMORY; - } - for (uint col_id = 0; col_id < table->s->fields; col_id++) { - m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns[col_id].hist_count = 0; + ctc_log_error("alloc mem failed, m_part_share->cbo_stats->ctc_cbo_stats_table size(%lu)", table->s->fields * sizeof(ctc_cbo_stats_column_t)); + return ERR_ALLOC_MEMORY; } + memset(m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns, 0, table->s->fields * sizeof(ctc_cbo_stats_column_t)); } ct_errno_t ret = (ct_errno_t)alloc_str_mysql_mem(m_part_share->cbo_stats, part_num, table);