日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL优化器cost计算

發(fā)布時(shí)間:2024/4/15 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL优化器cost计算 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

記錄MySQL 5.5上,優(yōu)化器進(jìn)行cost計(jì)算的方法。

第一篇: 單表的cost計(jì)算

數(shù)據(jù)結(jié)構(gòu):

1. table_share: 包含了表的元數(shù)據(jù),其中索引部分:

key_info:一個(gè)key的結(jié)構(gòu)體,代表一個(gè)索引,包含了:

  • key_length:key的長(zhǎng)度
  • key_parts:key一共有多少個(gè)column
  • key_part:key中具體的column
  • rec_per_key:相同的key平均有幾條記錄
  • 例如:

    (gdb) p (table->s->key_info->name) $16 = 0x8ca0ffbd "PRIMARY" (gdb) p (table->s->key_info->key_parts)$17 = 1 (gdb) p (table->s->key_info->rec_per_key)$18 = (ulong *) 0x8ca0ffe8

    2. JOIN:
    ? ? mysql_select函數(shù)中,創(chuàng)建了 new JOIN(thd, fields, select_options, result)對(duì)象,包含了當(dāng)前查詢的所有組件和各種轉(zhuǎn)換結(jié)果,其中 :

  • prepare:進(jìn)行一些等價(jià)交換之類的變化
  • optimize:選擇join的方式和access path
  • exec:根據(jù)執(zhí)行計(jì)劃運(yùn)行查詢
  • 3. join_tab:
    ? ? 包含了一個(gè)table訪問的cost等一些信息,經(jīng)過優(yōu)化后,填充這個(gè)結(jié)構(gòu)體

    cost的計(jì)算方法

    cost = cpu cost + io cost

  • cpu cost:server層對(duì)返回的記錄數(shù)的compare時(shí)間
  • io cost:引擎層根據(jù)掃描記錄的記錄數(shù)計(jì)算cost
  • 統(tǒng)計(jì)信息

    這里用到了兩部分統(tǒng)計(jì)信息:
    1. server層的統(tǒng)計(jì)信息,保存在table_share中。包括:

  • key_length
  • rec_per_key
  • block_size等
  • 2. innodb層的統(tǒng)計(jì)信息,包括:

  • stat_n_rows
  • stat_clustered_index_size
  • stat_sum_of_other_index_size
  • 主要函數(shù)調(diào)用

    make_join_statistics:
    --update_ref_and_keys: 添加可以使用的索引。
    --get_quick_record_count:
    ----test_quick_select: 評(píng)估每一個(gè)join table查詢得到的記錄數(shù),其中比較不同index的cost, 返回的記錄數(shù),選擇最優(yōu)的那個(gè)。
    choose plan:選擇join的順序

    實(shí)驗(yà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

    實(shí)驗(yàn)1: 單值查詢

    explain select * from xpchild where id =100;

    函數(shù)調(diào)用棧:

    make_join_statistics:
    ? ? table->quick_condition_rows= table->file->stats.records;
    ? ?if (s->type == JT_SYSTEM || s->type == JT_CONST)
    ? ?s->found_records=s->records=s->read_time=1; s->worst_seeks=1.0;

    結(jié)論:單key的查詢,join_tab的type=JT_CONST,索引record和read time都是1;最終得到的join->best_read=1.0;

    實(shí)驗(yàn)2: 范圍查詢

    explain select * from xpchild where id > 100;

    step1:update_ref_and_keys: 一共得到兩個(gè)possible index,

    step2:test_quick_select

    ? ?

    ?1. 計(jì)算全表掃描的cost:

    innodb全表掃描的io cost:

    innodb的io cost: s->read_time=(ha_rows) s->table->file->scan_time();
    innodb scan time:prebuilt->table->stat_clustered_index_size
    等于innodb這張表的聚簇索引的page個(gè)數(shù),本身innodb就是聚簇索引表,這里計(jì)算的io cost=16
    (gdb) p s->read_time
    $7 = 16

    MySQL server的cpu cost:

    scan_time= (double) records / TIME_FOR_COMPARE + 1;
    (gdb) p scan_time
    $16 = 1359.4000000000001

    總的cost:read_time= (double) head->file->scan_time() + scan_time + 1.1;

    (gdb) p read_time
    $18 = 1376.5

    ?

    繼續(xù)函數(shù)棧:

    根據(jù)possible index,生成sel_tree;
    get_best_group_min_max: 這里沒有使用到
    get_key_scans_params:根據(jù)sel_tree找到更好的cost

    ?

    2. 計(jì)算full index的cost

    ? ? ? find_shortest_key: 在覆蓋索引中選擇length最短的那個(gè)。
    ? ? ? get_index_only_read_time:這里如果有覆蓋索引(covering index)那么就會(huì)計(jì)算此覆蓋索引的cost。
    ? ? ? full index scan的計(jì)算方法:

    uint keys_per_block= (param->table->file->stats.block_size/2/(param->table->key_info[keynr].key_length+param->table->file->ref_length) + 1); read_time=((double) (records+keys_per_block-1)/(double) keys_per_block);

    ? ? ?這里假設(shè):一個(gè)塊中,只使用了一半的空間寫入數(shù)據(jù),
    ? ? ?如果計(jì)算的key_read_time > read_time, 則read_time= key_read_time,從此不再使用全表掃描。

    ?

    3. pk 索引計(jì)算的cost

    進(jìn)入get_key_scans_params函數(shù):選擇比傳入的read_time小的cost的執(zhí)行計(jì)劃,生成一個(gè)TRP_RANGE對(duì)象返回。

    ?

    step1: 評(píng)估范圍掃描的記錄數(shù)(check_quick_select)

    check_quick_keys:根據(jù)key,min,max值來評(píng)估記錄數(shù),并把records記錄到table->quick_rows[key]中,以便后續(xù)需要。

    (gdb) p *min_key $82 = 100 'd'

    ha_innobase::records_in_range: innodb引擎根據(jù)min和max值來評(píng)估記錄數(shù)。
    ? ? 計(jì)算方法:innodb對(duì)b_tree中范圍確定的page的個(gè)數(shù)和record_per_page進(jìn)行計(jì)算,當(dāng)評(píng)估>all_record/2時(shí),就取all_record/2。

    (gdb) p records $112 = 3396

    ?

    step 2: 計(jì)算cost

    根據(jù)pk range估算的records=3396,調(diào)整table->quick_condition_rows從全表的6792到現(xiàn)在的3396。
    計(jì)算cost:

    cpu_cost= (double) found_records / TIME_FOR_COMPARE; cpu_cost= 679.20000000000005
    io_cost = param->table->file->read_time(keynr,param->range_count,found_records);
    found_read_time = cpu_cost + io_cost + 0.01 found_read_time = 683.74750000000006

    這樣,通過pk掃描的cost遠(yuǎn)小于前面第一階段的全表掃描的代價(jià)。

    4. 計(jì)算普通索引的cost

    ? ? ?因?yàn)槎伎梢允褂们皩?dǎo)列進(jìn)行查詢,查詢的效率的差別在于非主鍵索引需要回到聚簇索引中查詢非索引列。
    所以,innodb返回的found_rows=6556(包含了掃描索引xpchild_id_c1 和primary key的), 所以最終計(jì)算的cost大于使用pk的cost。

    ? ? ? 最終計(jì)算得到的cost=7868.21 遠(yuǎn)高于pk索引的cost。

    ?

    結(jié)論: 最終選擇了pk的索引進(jìn)行range掃描

    ?

    下一篇實(shí)驗(yàn)待續(xù):關(guān)聯(lián)查詢。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/xpchild/p/3770823.html

    超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的MySQL优化器cost计算的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。