diff --git a/mysql-test/suite/ctc/r/ctc_bit_analyze.result b/mysql-test/suite/ctc/r/ctc_bit_analyze.result index 7d18c30ad10d8f8f6871520c82bc73360c0af50a..fccc1c3ad289360fe538761e5ae716d64a2b0b8c 100644 --- a/mysql-test/suite/ctc/r/ctc_bit_analyze.result +++ b/mysql-test/suite/ctc/r/ctc_bit_analyze.result @@ -44,7 +44,7 @@ Warnings: Note 1003 /* select#1 */ select `test`.`tbl_bit`.`num` AS `num` from `test`.`tbl_bit` where ((`test`.`tbl_bit`.`num` > 0x02) and (`test`.`tbl_bit`.`num` < 0x0d)) explain select * from tbl_bit where num >= b'0010' and num <= b'1101'; id select_type table partitions type possible_keys key key_len ref rows filtered Extra -1 SIMPLE tbl_bit NULL index idx_num idx_num 2 NULL 16 75.00 Using where; Using index +1 SIMPLE tbl_bit NULL range idx_num idx_num 2 NULL 12 100.00 Using where; Using index Warnings: Note 1003 /* select#1 */ select `test`.`tbl_bit`.`num` AS `num` from `test`.`tbl_bit` where ((`test`.`tbl_bit`.`num` >= 0x02) and (`test`.`tbl_bit`.`num` <= 0x0d)) drop table tbl_bit; diff --git a/storage/ctc/ctc_srv.h b/storage/ctc/ctc_srv.h index 345be8e2edf670034e4f19b3b09cf41874b90962..f65df4b3e75025426b222c0c6ba259396a0012d9 100644 --- a/storage/ctc/ctc_srv.h +++ b/storage/ctc/ctc_srv.h @@ -145,6 +145,8 @@ typedef struct { typedef struct { uint32_t estimate_rows; ctc_cbo_stats_column_t *columns; + uint32_t blocks; + uint32_t avg_row_len; } ctc_cbo_stats_table_t; /* @@ -161,6 +163,7 @@ typedef struct { uint32_t num_str_cols; bool *col_type; ctc_cbo_stats_table_t *ctc_cbo_stats_table; + uint32_t page_size; } ctc_cbo_stats_t; #pragma pack() diff --git a/storage/ctc/ctc_srv_mq_stub.cc b/storage/ctc/ctc_srv_mq_stub.cc index db4d8bd3fe2167f32ffcbe2371a51e977ec46df0..c7e99525f27898b7d38645d197bc1edb1ef9cfeb 100644 --- a/storage/ctc/ctc_srv_mq_stub.cc +++ b/storage/ctc/ctc_srv_mq_stub.cc @@ -771,16 +771,21 @@ void ctc_cbo_stats_copy_from_shm(ctc_handler_t *tch, ctc_cbo_stats_table_t *ctc_ bool is_part_table = stats->part_cnt ? true : false; stats->is_updated = req->stats->is_updated; stats->records = req->stats->records; + stats->page_size = req->stats->page_size; memcpy(stats->ndv_keys, req->stats->ndv_keys, stats->key_len); uint num_columns = req->stats->msg_len / sizeof(ctc_cbo_stats_column_t); if (!is_part_table) { *tch = req->tch; ctc_cbo_stats_table->estimate_rows = req->ctc_cbo_stats_table->estimate_rows; + ctc_cbo_stats_table->avg_row_len = req->ctc_cbo_stats_table->avg_row_len; + ctc_cbo_stats_table->blocks = req->ctc_cbo_stats_table->blocks; ctc_cbo_stats_columns_copy(ctc_cbo_stats_table->columns, req->ctc_cbo_stats_table->columns, stats, num_columns); } else { for (uint i = 0; i < req->num_part_fetch; i++) { ctc_cbo_stats_table[i].estimate_rows = req->ctc_cbo_stats_table[i].estimate_rows; + ctc_cbo_stats_table[i].avg_row_len = req->ctc_cbo_stats_table[i].avg_row_len; + ctc_cbo_stats_table[i].blocks = req->ctc_cbo_stats_table[i].blocks; ctc_cbo_stats_columns_copy(ctc_cbo_stats_table[i].columns, req->ctc_cbo_stats_table[i].columns, stats, num_columns); } diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index 178c2ae7c3515b18e6c225c7aaa696fd1b764db4..49604b211c130cc2edb6c21b7730a3b982e60c92 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -3369,6 +3369,59 @@ EXTER_ATTACK int ha_ctc::rnd_pos(uchar *buf, uchar *pos) { return ret; } +/** +The number of pages of table data is used as +the IO seek count for a full table scan. +*/ +double ha_ctc::scan_time() { + double scan_time = 0.0; + if (m_share && m_share->cbo_stats != nullptr) { + scan_time = m_share->cbo_stats->ctc_cbo_stats_table->blocks; + } + /* The min seek times */ + if (scan_time < 2.0) { + scan_time = 2.0; + } + return scan_time; +} + +/** +Calculate cost of 'index only' scan for given covering_index +and number of records to be scan. +*/ +double ha_ctc::index_only_read_time(uint keynr, double records_to_scan) { + double index_read_time; + uint32_t keys_per_block = (stats.block_size / 2 / + (table_share->key_info[keynr].key_length + ref_length) + 1); + index_read_time = ((double)(records_to_scan + keys_per_block - 1) / (double)keys_per_block); + return index_read_time; +} + +/** +Calculate the time it takes to read a set of ranges +through an non_covering_index. +*/ +double ha_ctc::read_time(uint index, uint ranges, ha_rows rows) { + if (index != table->s->primary_key) { + return (handler::read_time(index, ranges, rows)); + } + + if (rows <= 2) { + return (double)rows; + } + + /* + If the estimated records to be scanned exceeds the + total records in the table, use full_table_scan. + */ + double time_for_scan = scan_time(); + if (stats.records < rows) { + return time_for_scan; + } + + return (ranges + (double)rows / (double)stats.records * time_for_scan); +} + /** @brief ::info() is used to return information to the optimizer. See my_base.h for @@ -3410,7 +3463,10 @@ EXTER_ATTACK int ha_ctc::rnd_pos(uchar *buf, uchar *pos) { void ha_ctc::info_low() { if (m_share && m_share->cbo_stats != nullptr) { - stats.records = m_share->cbo_stats->ctc_cbo_stats_table->estimate_rows; + ctc_cbo_stats_table_t* stats_table = m_share->cbo_stats->ctc_cbo_stats_table; + stats.records = stats_table->estimate_rows; + stats.mean_rec_length = stats_table->avg_row_len; + stats.block_size = m_share->cbo_stats->page_size; } } @@ -5609,7 +5665,7 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } - *m_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr}; + *m_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr, 0}; m_share->cbo_stats->ctc_cbo_stats_table = (ctc_cbo_stats_table_t*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(ctc_cbo_stats_table_t), MYF(MY_WME)); if (m_share->cbo_stats->ctc_cbo_stats_table == nullptr) { diff --git a/storage/ctc/ha_ctc.h b/storage/ctc/ha_ctc.h index 44399d56bb7064af5f88dbc8ed91bc21f5123433..9c1fd859becf5ba6870c90e4b99092167965152d 100644 --- a/storage/ctc/ha_ctc.h +++ b/storage/ctc/ha_ctc.h @@ -515,43 +515,24 @@ public: uint max_supported_key_part_length( HA_CREATE_INFO *create_info) const override; - /** @brief - Called in test_quick_select to determine if indexes should be used. + /** + @brief Called in test_quick_select to determine if indexes should be used. + we assume that the data pages is equal to the disk scans times. + @return How many seeks it will take to read through the whole table. */ - virtual double scan_time() override { - DBUG_TRACE; - return (ulonglong)(stats.records + stats.deleted) / 100 + 2; - } + double scan_time() override; - /** @brief - This method will never be called if you do not implement indexes. + /** + @brief This method will never be called if you do not implement indexes. + @return estimated cost of 'index only' scan */ - virtual double read_time( - uint index, /*!< in: key number */ - uint ranges, /*!< in: how many ranges */ - ha_rows rows) /*!< in: estimated number of rows in the ranges */ override { - DBUG_TRACE; - - if (index != table->s->primary_key) { - /* Not clustered */ - return (handler::read_time(index, ranges, rows)); - } + virtual double index_only_read_time(uint keynr, double records) override; - if (rows <= 2) { - return ((double)rows); - } - - /* Assume that the read time is proportional to the scan time for all - rows + at most one seek per range. */ - - double time_for_scan = scan_time(); - - if (stats.records < rows) { - return (time_for_scan); - } - - return (ranges + (double)rows / (double)stats.records * time_for_scan); - } + /** + @brief This method will never be called if you do not implement indexes. + @return estimated time measured in disk seeks + */ + double read_time(uint index, uint ranges, ha_rows rows) override; bool inplace_alter_table( TABLE *altered_table MY_ATTRIBUTE((unused)), diff --git a/storage/ctc/ha_ctcpart.cc b/storage/ctc/ha_ctcpart.cc index 0db2188f254ede51cc9ed63b19c07220b4a7125b..30174a0053bc965f58130793a7f48fe2362c53b4 100644 --- a/storage/ctc/ha_ctcpart.cc +++ b/storage/ctc/ha_ctcpart.cc @@ -843,16 +843,46 @@ enum row_type ha_ctcpart::get_partition_row_type(const dd::Table *partition_tabl return ROW_TYPE_NOT_USED; } +double ha_ctcpart::scan_time() { + double scan_time = 0.0; + if (m_part_share && m_part_share->cbo_stats != nullptr) { + /* + For partitioned tables, queries can specify partitions to scan. + The cost of a full table scan should only include the specified partitions. + */ + uint part_num = m_is_sub_partitioned ? + table->part_info->num_parts * table->part_info->num_subparts : + table->part_info->num_parts; + for (uint i = m_part_info->get_first_used_partition(); i < part_num; + i = m_part_info->get_next_used_partition(i)) { + scan_time += m_part_share->cbo_stats->ctc_cbo_stats_table[i].blocks; + } + } + return scan_time; +} + void ha_ctcpart::info_low() { - stats.records = 0; - if (m_part_share->cbo_stats != nullptr) { - uint part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : - table->part_info->num_parts; - for (uint part_id = m_part_info->get_first_used_partition(); part_id < part_num; - part_id = m_part_info->get_next_used_partition(part_id)) { - stats.records += m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].estimate_rows; + stats.records = 0; + uint total_row_len = 0; + if (m_part_share && m_part_share->cbo_stats != nullptr) { + uint total_part_num = m_is_sub_partitioned ? + table->part_info->num_parts * table->part_info->num_subparts : + table->part_info->num_parts; + stats.block_size = m_part_share->cbo_stats->page_size; + uint curr_part_num = 0; + for (uint part_id = m_part_info->get_first_used_partition(); part_id < total_part_num; + part_id = m_part_info->get_next_used_partition(part_id)) { + stats.records += m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].estimate_rows; + if (m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].avg_row_len != 0) { + total_row_len += m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].avg_row_len; + curr_part_num++; + } + } + + if (curr_part_num > 0) { + stats.mean_rec_length = total_row_len / curr_part_num; + } } - } } int ha_ctcpart::info(uint flag) { @@ -1037,7 +1067,7 @@ int ha_ctcpart::initialize_cbo_stats() { ctc_log_error("alloc mem failed, m_part_share->cbo_stats size(%lu)", sizeof(ctc_cbo_stats_t)); return ERR_ALLOC_MEMORY; } - *m_part_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr}; + *m_part_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr, 0}; m_part_share->cbo_stats->part_cnt = part_num; @@ -1059,6 +1089,8 @@ int ha_ctcpart::initialize_cbo_stats() { 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].avg_row_len = 0; + m_part_share->cbo_stats->ctc_cbo_stats_table[i].blocks = 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) { diff --git a/storage/ctc/ha_ctcpart.h b/storage/ctc/ha_ctcpart.h index ec4f903b2df1b009c3bd9a6ffce1a2b9dd9e178f..e4c99ac18a7381879413c908a3d9f7a2d24382c9 100644 --- a/storage/ctc/ha_ctcpart.h +++ b/storage/ctc/ha_ctcpart.h @@ -398,6 +398,8 @@ class ha_ctcpart : public ha_ctc, bool equal_range_on_part_field(const key_range *start_key, const key_range *end_key); + double scan_time() override; + void info_low() override; int info(uint) override;