技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> MySQL --> MySQL数据库InnoDB存储引擎查询优化器实现的分析之统计信息

MySQL数据库InnoDB存储引擎查询优化器实现的分析之统计信息

浏览:1547次  出处信息

 1       统计信息

1.1      统计信息收集

show index from nkeys;

函数调用流程:

sql_parse.cc::mysql_execute_command(lex->sql_command == SQLCOM_SHOW_KEYS) ->
sql_show.cc::get_schema_stat_record ->

    1. ha_innobase::info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME)(info函数,实现统计信息收集功能,宏定义说明了需要收集的统计信息的类型) ->
    2. dict0dict.c::dict_update_statistics(ib_table)(HA_STATUS_TIME,指定此参数时进行统计信息的重新收集) ->
    3. dict_update_statistics_low(统计信息收集主函数,遍历表上的所有index,进行统计信息收集,设置到dict_index与dict_table结构之中) -> btr_estimate_number_of_different_key_vals ->

a)         dict_index

i.              索引总页面数;叶节点页面数

ii.              索引中不同键值个数,对于索引中的每一列,都需要计算。

for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++ )

  1. 随机在索引中定位BTR_KEY_VAL_ESTIMATE_N_PAGES = 8次页面。一定是8次,无论实际页面是否小于8.

next_rec = page_rec_get_next(rec);

cmp_rec_rec_with_match(rec, next_rec, &matched_fields);

  1. 读取页面中的索引项,与前一项进行对比。找到第一个不相同的列值后退出,matched_fields为相同列的个数。

for (j = matched_fields + 1; j <= n_cols; j++)

n_diff[j]++;

  1. 根据matched_fields,将所有之后的列对应的n_diff数组++,n_diff[j]++ (其中,n_cols为当前索引中,能够确定unique键值的索引列数)

for (j = 0; j <= n_cols; j++)

index->stat_n_diff_key_vals[j] =

((n_diff[j] *index->stat_n_leaf_pages +

BTR_KEY_VAL_ESTIMATE_N_PAGES +

total_external_size + not_emptry_flag) /

(BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size)

  1. 随机8个page扫描完毕,根据统计信息n_diff,计算最终的index中,每一列不同取值的数量(注意,此处是每一列的不同取值的数量,而非rec_per_key)。

b)         dict_table

i.              表总行数。table->stat_n_rows = index->stat_n_diff_key_vals[dict_index_get_n_unique(index)]; 总行数,为表第一个索引,unique key的个数。

ii.              聚簇索引页面数

iii.              二级索引页面数

iv.              table->stat_initialized = 1; 统计信息为重新收集的

v.              table->stat_modified_counter = 0; 信息收集之后,表上无DML操作发生,统计信息是准确的

 

  1. 回到info函数,如果调用info函数时,指定了参数HA_STATUS_CONST,那么info函数将会更新表中每一个索引,每一个索引对应的每一个列组合的rec_per_key取值。(例如:考虑nkeys表的c1c2索引,那么将会计算rec_per_key(c1), rec_per_key(c1c2)的取值,而不会计算rec_per_key(c2),单独指定c2列无意义,并不会选择c1c2索引进行查询)。

 

a)         计算rec_per_key

for (I = 0; I < table->s->keys; i++)                                          // 遍历索引

for (j = 0; j < table->key_info[i].key_parts; j++)        // 遍历索引中的所有列

rec_per_key = records / (index->stat_n_diff_key_vals[j+1]);

根据前面收集的不同键值数量,与表记录数量,计算最终,rec_per_key的取值。

b)         调整rec_per_key

rec_per_key = rec_per_key / 2;

由于mysql查询优化,更倾向于使用全表扫描,因此在此处做调整,将rec_per_key减半,减少索引range查询返回记录数,提高查询优化选择索引的概率。

 

1.2     统计信息更新

在以下过程中,INNODB将会更新表的统计信息:

  • analyze table

ha_innobase::analyze ->

info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE)

  • open table

ha_innobase::open -> 第一次open表时需要调用,后续的open,都不调用

info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST)

  • 查询优化前,此时不重新收集统计信息,只计算

sql_select.cc::make_join_statistics ->

info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);

1.3     统计信息收集总结

  • 在第一次open table时,会重新收集全表统计信息,因此第一次open table是较慢的过程。庆幸的是,Innodb会将打开的表cache起来,因此并不会多次open。
  • 结合mysql上层的查询优化可知,range查询优化并不会使用open table过程中收集的统计信息。在此处看来,也无法使用,因为mysql收集的统计信息过于简单,只能回答rec_per_key,无法回答rec_in_range,rec_in_range需要通过调用records_in_range函数计算。
  • records_in_table,rec_per_key统计信息,在mysql多表join时使用。多表join,ref的属性,在语句执行前,并不能获得key取值,因此只能通过rec_per_key预估join的内表将会返回多少记录。
  • 是否可以借鉴oracle中的执行计划,硬解析与软解析分离的实现思路?同样为mysql保留执行计划,降低查询优化的代价。从以上的分析看来,mysql的查询优化,并不如想象中高效,同样是一个缓慢的过程。

2       查询优化总结

释放可以借鉴oracle中的统计信息持久化策略,持久化rec_per_key,records_in_table两类十分重要的统计信息,持久化统计信息,基本上能够保证mysql join操作的执行计划的稳定性。

本系列文章主目录:MySQL数据库InnoDB存储引擎查询优化器实现的分析

建议继续学习:

  1. Mysql查询优化器浅析(上)    (阅读:2502)
  2. MySQL数据库InnoDB存储引擎查询优化器实现的分析之单表查询    (阅读:2362)
  3. Mysql查询优化器浅析(下)    (阅读:2051)
  4. MySQL数据库InnoDB存储引擎查询优化器实现的分析之单表unique查询    (阅读:1971)
  5. MySQL数据库InnoDB存储引擎查询优化器实现的分析    (阅读:1876)
  6. MySQL数据库InnoDB存储引擎查询优化器实现的分析之多表简单JOIN查询    (阅读:1845)
  7. MySQL数据库InnoDB存储引擎查询优化器实现的分析之optimizer_search_depth参数    (阅读:1775)
  8. MySQL数据库InnoDB存储引擎查询优化器实现的分析之附录    (阅读:1743)
  9. MySQL数据库InnoDB存储引擎查询优化器实现的分析之best_access_path函数分析    (阅读:1445)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1