page0cur.cc page0page.h page0page.cc rem0cmp.cc
為什么談及定位方法,因?yàn)樵趇nnodb中,比如一個(gè)插入語(yǔ)句我們需要定位在哪里插入(PAGE_CUR_LE),比如一個(gè)查詢語(yǔ)句我們需要定位到其第一個(gè)需要讀取數(shù)據(jù)的位置,因此定位方法是查詢的根本。而找到這個(gè)記錄位置后實(shí)際上是用一個(gè)叫做page_cur_t結(jié)構(gòu)體進(jìn)行存儲(chǔ),暫且叫他cursor游標(biāo)
我們提供的服務(wù)有:做網(wǎng)站、網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、洮南ssl等。為上千企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的洮南網(wǎng)站制作公司
struct page_cur_t{
const dict_index_t* index;
rec_t* rec; /*!< pointer to a record on page */
ulint* offsets;
buf_block_t* block; /*!< pointer to the block containing rec */
}; 其中包含了本index的數(shù)據(jù)字典類容、實(shí)際的數(shù)據(jù)、記錄所在塊的信息等,下面我具體談一下定位方法,同時(shí)結(jié)合源碼來(lái)看它具體的實(shí)現(xiàn)。
我們先來(lái)明確一下概念:
可自行參考運(yùn)維內(nèi)參等其他書(shū)籍,這里就在簡(jiǎn)單描述到這里,本文會(huì)出現(xiàn)相關(guān)術(shù)語(yǔ)。
在innodb中的常用的search mode有如下幾個(gè)
/* Page cursor search modes; the values must be in this order! */
enum page_cur_mode_t {
PAGE_CUR_UNSUPP = 0,
PAGE_CUR_G = 1,
PAGE_CUR_GE = 2,
PAGE_CUR_L = 3,
PAGE_CUR_LE = 4,
};
我們來(lái)討論一個(gè)問(wèn)題考慮如下有序的數(shù)組
1,2,3,3,4,5,6,7
如果我們查詢>=3(PAGE_CUR_GE)和<3(PAGE_CUR_L),那么自然我們需要將位置定位到2到3之間我們且用2-3表示
如果我們查詢<=3(PAGE_CUR_LE)和>3(PAGE_CUR_G),那么自然我們需要將位置定位到3到4之間我們且用3-4表示
那么我們將這里的區(qū)間兩個(gè)值記為low-high
仔細(xì)分析后我們發(fā)現(xiàn)另外一個(gè)規(guī)律
為什么講這個(gè)東西,因?yàn)檫@兩個(gè)規(guī)律在innodb記錄定位中起到了關(guān)鍵作用,也直接影響到了innodb記錄查找的二分算法的實(shí)現(xiàn)方式。
大家在源碼中能看到matched_fields和matched_bytes兩個(gè)值,那么他們代表什么意思呢?
以int類型為例,因?yàn)樵诤瘮?shù)cmp_dtuple_rec_with_match_bytes是逐個(gè)字段逐個(gè)字節(jié)進(jìn)行比較的,關(guān)鍵代碼如下
while (cur_field < n_cmp) {
rec_byte = *rec_b_ptr++;
dtuple_byte = *dtuple_b_ptr++;} 比如int 2,int 3在innodb中內(nèi)部表示為0X80000002和0X80000003,如果他們進(jìn)行比較那么最終此field的比較為不相等(-1),那么matched_fields=0但是
switch (type->mtype) {
case DATA_FIXBINARY:
case DATA_BINARY:
case DATA_INT:
case DATA_SYS_CHILD:
case DATA_SYS:
break;
case DATA_BLOB:
if (type->prtype & DATA_BINARY_TYPE) {
break;
}
default:
ret = cmp_data(type->mtype, type->prtype,
dtuple_b_ptr, dtuple_f_len,
rec_b_ptr, rec_f_len);
if (!ret) {
goto next_field;
}
cur_bytes = 0;
goto order_resolved;
} 具體可以參考一下源碼,這里不再過(guò)多解釋
為什么叫做再析,因?yàn)槿邕\(yùn)維內(nèi)參已經(jīng)對(duì)本函數(shù)進(jìn)行了分析,這里主要分析查詢模式對(duì)二分法實(shí)現(xiàn)的影響,并且用圖進(jìn)行說(shuō)明你會(huì)有新的感悟!當(dāng)然如果你對(duì)什么slot還不清楚請(qǐng)自行參考運(yùn)維內(nèi)參
簡(jiǎn)單的說(shuō)page_cur_search_with_match_bytes會(huì)調(diào)用cmp_dtuple_rec_with_match_bytes函數(shù)進(jìn)行元組和記錄之間的比較,而塊內(nèi)部比較方法就是先對(duì)所有的slot進(jìn)行二分查找確定到某個(gè)slot以快速縮小范圍,然后在對(duì)slot內(nèi)部使用類似二分查找的方法等到記錄,我們主要來(lái)分析一下slot內(nèi)部的類二分法,因?yàn)樗耆俏覀儾樵兡J街袃蓚€(gè)規(guī)律的完美體現(xiàn),如下簡(jiǎn)化的代碼片段以及我寫(xiě)的注釋:
/* Perform linear search until the upper and lower records come to
distance 1 of each other. */
while (page_rec_get_next_const(low_rec) != up_rec) { //如果low_rec和up_rec相差1則結(jié)束循環(huán),否則繼續(xù)
mid_rec = page_rec_get_next_const(low_rec);//這里并沒(méi)有除以2作為mid_rec而是簡(jiǎn)單的取下一行,因?yàn)閞ec是單鏈表這樣顯然很容易完成
ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
low_matched_fields, low_matched_bytes,
up_matched_fields, up_matched_bytes);
offsets = rec_get_offsets(
mid_rec, index, offsets_,
dtuple_get_n_fields_cmp(tuple), &heap);//獲得記錄的各個(gè)字段的偏移數(shù)組
cmp = cmp_dtuple_rec_with_match_bytes(
tuple, mid_rec, index, offsets,
&cur_matched_fields, &cur_matched_bytes);//進(jìn)行比較 0為相等 1 元組大于記錄 -1記錄大于元組,并且傳出field和bytes
if (cmp > 0) { //如果元組大于mid_rec記錄
low_rec_match://當(dāng)然簡(jiǎn)單的將mid_rec指針賦予給low_rec即可
low_rec = mid_rec;
low_matched_fields = cur_matched_fields;
low_matched_bytes = cur_matched_bytes;
} else if (cmp) { //如果元組小于mid_rec記錄
up_rec_match://當(dāng)然簡(jiǎn)單的將mid_rec指針賦予給up_rec即可,這一步可以跳過(guò)很多記錄
up_rec = mid_rec;
up_matched_fields = cur_matched_fields;
up_matched_bytes = cur_matched_bytes;
}
//下面是相等情況的判斷非常關(guān)鍵符合我們規(guī)律1算法
//如果元組等于mid_rec
else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE //如果是>(PAGE_CUR_G)和<=(PAGE_CUR_LE)
) {
goto low_rec_match; //執(zhí)行l(wèi)ow_rec_match
} else //如果是>=(PAGE_CUR_GE)和<(PAGE_CUR_L)
{
goto up_rec_match;//執(zhí)行up_rec_match
}
}
//下面體現(xiàn)我們的規(guī)律2算法
//如果是> PAGE_CUR_G和>= PAGE_CUR_GE 都是取high
//如果是< PAGE_CUR_L和<= PAGE_CUR_LE 都是取low
//因?yàn)槭莈num類型直接比較
if (mode <= PAGE_CUR_GE) {
page_cur_position(up_rec, block, cursor);
} else {
page_cur_position(low_rec, block, cursor);
}
*iup_matched_fields = up_matched_fields;
*iup_matched_bytes = up_matched_bytes;
*ilow_matched_fields = low_matched_fields;
*ilow_matched_bytes = low_matched_bytes; 注意一個(gè)slot的own記錄為最多8條如下定義:
/* The maximum and minimum number of records owned by a directory slot. The number may drop below the minimum in the first and the last slot in the directory. */ #define PAGE_DIR_SLOT_MAX_N_OWNED 8 #define PAGE_DIR_SLOT_MIN_N_OWNED 4
如果大于了8則進(jìn)行分裂
if (n_owned == PAGE_DIR_SLOT_MAX_N_OWNED) {
page_dir_split_slot(
page, NULL,
page_dir_find_owner_slot(owner_rec));
} 下面我們畫(huà)一個(gè)slot內(nèi)部定位的圖,我們以如下有序數(shù)據(jù)為例,假設(shè)每一個(gè)數(shù)字代表一個(gè)記錄(rec)
1 2 2 2 3 3 4 4
我們可以看到有大量重復(fù)的記錄,但是本算法也可以進(jìn)行精確的定位,我們約定:
mid為2顯然已經(jīng)等于了元組的中的2,如圖

但是查詢模式為PAGE_CUR_G 做low_rec_match操作、并且將mid取向下一條記錄后如圖

mid為2顯然已經(jīng)等于了元組的中的2,但是查詢模式為PAGE_CUR_G做low_rec_match后、并且將mid取向下一條記錄如圖

mid為2顯然已經(jīng)等于了元組的中的2,但是查詢模式為PAGE_CUR_G做low_rec_match后、并且將mid取向下一條記錄如圖

mid為3顯然已經(jīng)大于了元組中的2,做up_rec_match后我們發(fā)現(xiàn)記錄定位成功,為low 2-high 3。page_rec_get_next_const(low_rec) == up_rec 循環(huán)退出如圖

因?yàn)槲覀兊牟樵兡J绞荘AGE_CUR_G所以我們執(zhí)行page_cur_position(up_rec, block, cursor);取high值如圖

mid為2顯然小于元組的中的3,如圖

做low_rec_match操作、并且將mid取向下一條記錄后如圖

mid為2顯然小于元組的中的3,做low_rec_match操作、并且將mid取向下一條記錄后如圖

mid為2顯然小于元組的中的3,做low_rec_match操作、并且將mid取向下一條記錄后如圖

mid為3顯然等于元組的中的3,但是查詢模式為PAGE_CUR_L做up_rec_match后、我們發(fā)現(xiàn)記錄定位成功為low 2-high 3.page_rec_get_next_const(low_rec) == up_rec 循環(huán)退出如圖

因?yàn)槲覀兊牟樵兡J绞荘AGE_CUR_L所以我們執(zhí)行page_cur_position(low_rec, block, cursor);取low值如圖

我們slot內(nèi)部的記錄并不多最多為8條,二分算法slot內(nèi)部并沒(méi)有使用二分而是使用了取下一個(gè)記錄的值的指針,非常容易實(shí)現(xiàn)因?yàn)橛涗浿斜緛?lái)就包含了下一條記錄的偏移量,并且通過(guò)訪問(wèn)模式兩個(gè)規(guī)律將重復(fù)值過(guò)濾掉,最終找到邊界。總之分析之后發(fā)現(xiàn)是一種精確高效的算法。
網(wǎng)站標(biāo)題:關(guān)于innodb中查詢的定位方法
文章來(lái)源:http://chinadenli.net/article8/gsjjip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站收錄、域名注冊(cè)、定制開(kāi)發(fā)、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)