mysql join大小表顺讯_MySQL优化器join顺序
前一篇介紹了cost的計(jì)算方法,下面測試一下兩表關(guān)聯(lián)的查詢:
測試用例
CREATE TABLE `xpchild` (
`id` int(11) NOT NULL,
`name` varchar(100) DEFAULT NULL,
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `xpchild_name` (`name`),
KEY `xpchild_id_c1` (`id`,`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `xpchild_1` (
`xxid` bigint(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
KEY `xpchild_1_id` (`xxid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
測試sql
select * from xpchild, xpchild_1 where xpchild.id=100 and xpchild.id=xpchild_1.xxid;
函數(shù)調(diào)用棧:
JOIN::optimize
make_join_statistics
update_ref_and_keys
get_quick_record_count
choose_plan
以上省略了JOIN::prepare的過程,prepare主要進(jìn)行一些等級(jí)變化,上面的sql是一個(gè)比較簡單的兩表關(guān)聯(lián),并不會(huì)進(jìn)行過多的變換。
step1: 初始化
make_join_statistics:
根據(jù)select_lex->leaf_tables初始化每個(gè)JOIN_TAB對象,至此,一個(gè)sql對于一個(gè)join,對應(yīng)兩個(gè)join_tab.
初始化quick_condition_rows為innodb中的stat統(tǒng)計(jì)信息中的record記錄數(shù)。
step 2: 查詢可用索引
update_ref_and_keys:根據(jù)where條件,選擇可以使用的索引,加入到possible keys中,本例子加入的keys包括:
xpchild: primary,xpchild_id_c1
xpchild_1: xxid
(gdb) p *keyuse_array
$67 = {
buffer = 0x8ca1fb58 "@24214",
elements = 3,
max_element = 20,
alloc_increment = 64,
size_of_element = 48
step 3: 計(jì)算cost
get_quick_record_count:根據(jù)可選擇的possible_keys計(jì)算cost。
1. xpchild表
因?yàn)橛锌梢允褂玫膒rimary,xpchild表s->type == JT_CONST,所以cost的計(jì)算為:
s->found_records=s->records=s->read_time=1。
所以,mysql對于使用primary,unique key的使用上比較有傾向性,而且可以節(jié)省大量的計(jì)算cost的時(shí)間。
2. xpchild_1表:
全表掃描的records && read_time是:
s->found_records= 1215
s->read_time= 5
計(jì)算xxid索引的cost:
get_quick_record_count
test_quick_select:
最終計(jì)算的cost:
estimated_records=1
best_read_time=2.21
具體的計(jì)算方式,可以參考前面一篇博客
到此:xpchild的JOIN_TAB結(jié)構(gòu)中,比較簡單,const table類型,cost=1;
xpchild_1的JOIN_TAB結(jié)構(gòu)中,found_records=1, read_time=2.21;
對于單表的的查詢access path已經(jīng)是最優(yōu)的。
step 4:join的順序:
choose_join:
1. 如果是const table;不再進(jìn)行join順序的計(jì)算,直接選擇使用當(dāng)前positions。
memcpy((uchar*) join->best_positions,(uchar*) join->positions,sizeof(POSITION)*join->const_tables);
join->best_read=1.0;
2. 為非const table,選擇最優(yōu)的訪問順序
optimizer_search_depth:優(yōu)化訪問表join順序的遞歸計(jì)算深度。
straight_join:按照sql的順序,或者添加sql hint確定的順序,默認(rèn)不使用
greedy_search:貪婪算法,對于當(dāng)前的查詢,在候選的表中,選擇一個(gè)最小cost添加到當(dāng)前的plan中,遞歸完成。
best_extension_by_limited_search:根據(jù)current_record_count,與調(diào)用best_access_path得到的best_record_count進(jìn)行比較,選擇最優(yōu)的路徑。
best_access_path:table->quick_rows根據(jù)前面計(jì)算的records,得出cost,得到j(luò)oin->positions[idx]的最優(yōu)路徑。
join順序選擇的步驟:
1. 根據(jù)best_extension_by_limited_search在remaining table中選擇cost最小的那個(gè),本例中,xpchild的cost為:records=1 , read_time=0。所以選擇為第一張表。
2. 然后從候選表中選擇一個(gè)(只剩下xpchild_1表)加入到j(luò)oin的順序中,并根據(jù)best_access_path選擇一個(gè)cost最低的執(zhí)行計(jì)劃加入到plan中,這里選擇xpchild_1_id的索引。
最后得到best plan,并賦值給last_query_cost;
join->thd->status_var.last_query_cost= join->best_read;
最后得到的best plan:
(gdb) p tab->join->best_read
$73 = 1.1990000000000001
(gdb) p tab->join->best_positions
$72 = {{
records_read = 1,
read_time = 0,
table = 0x8ca06078, 'xpchild'
key = 0x8ca1fb58, 'primary'
ref_depend_map = 0
}, {
records_read = 1,
read_time = 1,
table = 0x8ca0620c, 'xpchild_1'
key = 0x8ca1fbb8, 'xpchild_1_id'
ref_depend_map = 0
}
未完待續(xù):
總結(jié)
以上是生活随笔為你收集整理的mysql join大小表顺讯_MySQL优化器join顺序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 抗战时期湖北省那个地区有一支陜军坚持了多
- 下一篇: 高性能mysql 第六章_高性能MySQ