---
成都創(chuàng)新互聯(lián)是一家專注于網(wǎng)站設(shè)計、網(wǎng)站制作與策劃設(shè)計,故城網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:故城等地區(qū)。故城做網(wǎng)站價格咨詢:028-86922220
這是開發(fā)問的一個問題
---
###一、問題描述
如果一個表有一個聯(lián)合索引 (a,b):
索引記錄如下:
id1 id2
1 10
1 10
1 10
2 20
2 20
3 30
3 30
意思就是說通過a進(jìn)行過濾的數(shù)據(jù)和通過a和b過濾的數(shù)據(jù)條數(shù)一樣,如果要通過索引訪問數(shù)據(jù)select * from table where id1=1 和 select * from table where id1=1 and id2=10 是不是效率一致?
###二、簡易分析
首先對于數(shù)據(jù)查找,首先第一步是進(jìn)行innodb層數(shù)據(jù)的定位(也就是從什么位置開始輸出數(shù)據(jù)給MySQL層),然后定位完成后,順序向下訪問就行了,因為innodb 的表示一個索引組織表。
- 對于等值條件,Innodb層會多訪問下一條數(shù)據(jù),如果不符合要求了則表示結(jié)束了,會返回一個DB_RECORD_NOT_FOUND標(biāo)記給MySQL層表示結(jié)束。
- 對于 范圍 比如 > and < 操作如果使用了索引,那么<操作要么在MySQL層進(jìn)行判斷結(jié)束,要買使用ICP在Innodb做一層過濾。
對于數(shù)據(jù)定位后的順序訪問而言,沒有什么差別。
因此這個問題主要的問題轉(zhuǎn)換為, a=* 和 a=* and b=* 在進(jìn)行數(shù)據(jù)定位的時候效率是否一致,對于這個問題來講因為a=* 和 a=* and b=* 返回的數(shù)據(jù)是一樣。所謂數(shù)據(jù)定位找到數(shù)據(jù)返回的起點在什么地方,這個過程一般會通過B+數(shù)定位到葉子節(jié)點,然后根據(jù)在葉子節(jié)點內(nèi)部使用二分法進(jìn)行比較,加速定位,比較的方法就是根據(jù)字段個數(shù)逐個比較(函數(shù)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) {
```
n_cmp就是需要比較的個數(shù)。
debug 記錄:
```
a=*記錄
829 ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
(gdb) n
830 ut_ad(cur_field <= n_cmp);
(gdb) p n_cmp
$4 = 1
a=* and b=* 記錄
829 ut_ad(n_cmp <= dtuple_get_n_fields(dtuple));
(gdb) n
830 ut_ad(cur_field <= n_cmp);
(gdb) p n_cmp
$5 = 2
```
因此結(jié)論:如果這種特殊情況下,我認(rèn)為效率應(yīng)該基本一致,僅僅區(qū)別就在于定位比較的時候使用字段的多少,但這不會是語句的最大性能耗用點,最大的應(yīng)該是循環(huán)訪問所有的字段和通過主鍵回表。因此盡量寫自己需要的字段。
深入理解MySQL主從原理:https://www.jianshu.com/nb/43148932
個人微信:gaopp_22389860