—
这是开发问的一个问题
—
###一、问题描述
如果一个表有一个联合索引 (a,b):开发云主机域名
索引记录如下:
id1 id2
1 10
1 10
1 10
2 20
2 20
3 30
3 30
意思就是说通过a进行过滤的数据和通过a和b过滤的数据条数一样,如果要通过索引访问数据select * from table where id1=1 和 select * from table where id1=1 and id2=10 是不是效率一致?
###二、简易分析
首先对于数据查找,首先第一步是进行innodb层数据的定位(也就是从什么位置开始输出数据给MySQL层),然后定位完成后,顺序向下访问就行了,因为innodb 的表示一个索引组织表。
– 对于等值条件,Innodb层会多访问下一条数据,如果不符合要求了则表示结束了,会返回一个DB_RECORD_NOT_FOUND标记给MySQL层表示结束。
– 对于 范围 比如 > and
对于数据定位后的顺序访问而言,没有什么差别。
因此这个问题主要的问题转换为, a=* 和 a=* and b=* 在进行数据定位的时候效率是否一致,对于这个问题来讲因为a=* 和 a=* and b=* 返回的数据是一样。所谓数据定位找到数据返回的起点在什么地方,这个过程一般会通过B+数定位到叶子节点,然后根据在叶子节点内部使用二分法进行比较,加速定位,比较的方法就是根据字段个数逐个比较(函数cmp_dtuple_rec_with_match_bytes),比如a=* 那么需要比较就是一个,如果a=* and b=* 那么比较的字段就是2个。
代码大概的栈
“`
->row_search_mvcc
->btr_pcur_open_with_no_init_func
-> btr_cur_search_to_nth_level
-> page_cur_search_with_match_bytes
-> cmp_dtuple_rec_with_match_bytes
“`
cmp_dtuple_rec_with_match_bytes 这部分注释如下:
“`
/* Match fields in a loop; stop if we run out of fields in dtuple
or find an externally stored field */
while (cur_field
“`
n_cmp就是需要比较的个数。
debug 记录:
“`
a=*记录
829 ut_ad(n_cmp
(gdb) n
830 ut_ad(cur_field
(gdb) p n_cmp
$4 = 1
a=* and b=* 记录
829 ut_ad(n_cmp
(gdb) n
830 ut_ad(cur_field
(gdb) p n_cmp
$5 = 2
“`
因此结论:如果这种特殊情况下,我认为效率应该基本一致,仅仅区别就在于定位比较的时候使用字段的多少,但这不会是语句的最大性能耗用点,最大的应该是循环访问所有的字段和通过主键回表。因此尽量写自己需要的字段。
深入理解MySQL主从原理:https://www.jianshu.com/nb/43148932
个人微信:gaopp_22389860
查看表上的索引状态:SHOW INDEX returns table index information.SHOW KEYS and SHOW INDEXES are synonyms for SHOW INDEX.开发云主机域名语法:show {index|…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。