mysql join優(yōu)化策略

mysql join使用的規(guī)則以及注意事項

join 算法分類
  • NLJ 算法蘑斧,白話,以及觸發(fā)的時機
    • 兩個或多個表join查詢的時候烈涮,在查詢被驅動表的時候走索引查詢适揉,驅動表查詢被驅動表的時候,是從驅動表中一條條去查詢被驅動表
  • BNL 算法聪轿,白話爷肝,以及觸發(fā)的時機
    • 兩個或多個表join查詢的時候,在查詢被驅動表的時候非索引查詢陆错,將驅動表存放的join-buffer中灯抛,然后全表掃描被驅動表,在內(nèi)存中進行匹配過濾的算法音瓷,主要耗費在過濾的時候計算數(shù)據(jù)太大
  • NLJ 算法的升級優(yōu)化 ---》 MRR(索引順序讀)算法
    • 驅動表一條條查詢被驅動表的時候对嚼,索引順序可能是隨機,而且不是批量绳慎;改進的方式就是將索引統(tǒng)一在內(nèi)存中排序纵竖,然后批量查詢被驅動表漠烧,數(shù)據(jù)庫中默認不支持,因此需要手動開啟
    • set optimizer_switch="mrr_cost_based=off"
      
    • 嘗試的使用了一下靡砌,發(fā)現(xiàn)如果開啟mrr的話已脓,普通的查詢速度會有所下降,原因未知通殃;
  • NLJ 算法的升級優(yōu)化 ---》BAK(批量讀) 算法
    • mrr算法的提升摆舟,批量將驅動表上的索引在被動表上進行順序查找
  • join使用臨時表進行優(yōu)化查詢的方式
    • 假如A,B兩個表需要進行join查詢,但是B表上對應的字段沒有添加索引邓了,而且在業(yè)務上也沒有必要添加索引,如果此時直接進行查詢的話媳瞪,算法是BNL算法骗炉,會導致在內(nèi)存中的計算量過大,因此最好的方式是利用臨時表的特性進行處理
      create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;
      insert into temp_t select * from t2 where b>=1 and b<=2000;
      select * from t1 join temp_t on (t1.b=temp_t.b);
    
  • 使用hash join進行優(yōu)化查詢
    • 上述問題還可以直接使用業(yè)務邏輯上進行處理蛇受,也就是所說的hash-join句葵,以小表作為驅動表,然后存入hash兢仰,在全表掃描打表乍丈,直接去進行hash判斷,這樣的話把将,計算的數(shù)據(jù)也就是打表的全量數(shù)據(jù)
  • BNL算法在使用過程中對數(shù)據(jù)庫IO和數(shù)據(jù)庫緩存的影響轻专,如何影響B(tài)ufffer Pool的LRU算法;
  • 在使用BNL查詢的時候察蹲,buffer-pool 中l(wèi)ru的規(guī)則是请垛,首先將數(shù)據(jù)放到old區(qū),如果1秒后有使用的話洽议,將數(shù)據(jù)移動到頭部宗收,因為是bnl在查詢的時候,會進行不斷的掃描內(nèi)存中的數(shù)據(jù)亚兄,如果對象大的話混稽,可能會在幾秒一個輪回,導致這些冷數(shù)據(jù)移動到了buffer-pool的頭部审胚,影響正常數(shù)據(jù)的命中匈勋;
  • 大表join操作雖然對IO有影響,但是在語句執(zhí)行結束后菲盾,對IO的影響也就結束了颓影。但是,對Buffer Pool的影響就是持續(xù)性的懒鉴,需要依靠后續(xù)的查詢請求慢慢恢復內(nèi)存命中率诡挂。
    為了減少這種影響碎浇,你可以考慮增大join_buffer_size的值,減少對被驅動表的掃描次數(shù)璃俗。
    也就是說奴璃,BNL算法對系統(tǒng)的影響主要包括三個方面:
    1 可能會多次掃描被驅動表,占用磁盤IO資源城豁;
    2 判斷join條件需要執(zhí)行M*N次對比(M苟穆、N分別是兩張表的行數(shù)),如果是大表就會占用非常多的CPU資源唱星;
    3 可能會導致Buffer Pool的熱數(shù)據(jù)被淘汰雳旅,影響內(nèi)存命中率。
  • 多張表聯(lián)查的時候间聊,優(yōu)化方案設計

select * from t1 join t2 on(t1.a=t2.a) join t3 on (t2.b=t3.b) where t1.c>=X and t2.c>=Y and t3.c>=Z;

-- 初始化表
CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
create table t2 like t1;
create table t3 like t2;

delimiter;;
CREATE PROCEDURE idata ( ) 
BEGIN
  DECLARE i INT;
  SET i = 1;
  WHILE
          ( i <= 1000 ) DO
          INSERT INTO t1
      VALUES
          ( i, 1000-i, i, 1000-i );
      SET i = i + 1;  
  END WHILE;  
END;;
delimiter;

insert into t2 (select *  from t1);
insert into t2 (select *  from t1);

-- 開啟mrr算法和bka算法
SET optimizer_switch = 'mrr=on,mrr_cost_based=off,batched_key_access=on';

-- 假如 X>Y>Z,也就是t1 是驅動表攒盈,需要在t1上建立一個索引,c哎榴;在執(zhí)行sql的時候型豁,explain查看是否使用索引

-- 如果沒有使用索引直接強制使用c  --》EXPLAIN select * from t1 force index(c) ,確保驅動表盡可能的小
ALTER TABLE t1 ADD INDEX `c` ( c );

-- 給t2表的a字段加上索引,將BNL算法優(yōu)化成BKA算法
alter table t2 add index `a` (a);

-- 同理給t3表的b字段上加上索引尚蝌,將BNL算法優(yōu)化成BKA算法
alter table t3 add index `b` (b);

-- 最終的sql形式因為我的t1表的索引一直不走c因此強制加上索引
EXPLAIN select * from t1 force index(c) LEFT JOIN t2 on(t1.a=t2.a) LEFT JOIN t3 on (t2.b=t3.b) where t1.c>=300 and t2.c>=200 and t3.c>=100;
-- 結果
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: t1
 partitions: NULL
       type: range
possible_keys: c
        key: c
    key_len: 5
        ref: NULL
       rows: 700
   filtered: 100.00
      Extra: Using index condition
*************************** 2. row ***************************
         id: 1
select_type: SIMPLE
      table: t2
 partitions: NULL
       type: ref
possible_keys: a,c
        key: a
    key_len: 5
        ref: testJoin.t1.a
       rows: 1
   filtered: 80.00
      Extra: Using where
*************************** 3. row ***************************
         id: 1
select_type: SIMPLE
      table: t3
 partitions: NULL
       type: ref
possible_keys: b,c
        key: b
    key_len: 5
        ref: testJoin.t2.b
       rows: 1
   filtered: 90.00
      Extra: Using where
3 rows in set, 1 warning (0.00 sec)

整體的思路就是迎变,盡量讓每一次參與join的驅動表的數(shù)據(jù)集,越小越好飘言,因為這樣我們的驅動表就會越小

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衣形,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子姿鸿,更是在濱河造成了極大的恐慌泵喘,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件般妙,死亡現(xiàn)場離奇詭異纪铺,居然都是意外死亡,警方通過查閱死者的電腦和手機碟渺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門鲜锚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苫拍,你說我怎么就攤上這事芜繁。” “怎么了绒极?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵骏令,是天一觀的道長。 經(jīng)常有香客問我垄提,道長榔袋,這世上最難降的妖魔是什么周拐? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮凰兑,結果婚禮上妥粟,老公的妹妹穿的比我還像新娘。我一直安慰自己吏够,他們只是感情好勾给,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锅知,像睡著了一般播急。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上售睹,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天旅择,我揣著相機與錄音,去河邊找鬼侣姆。 笑死,一個胖子當著我的面吹牛沉噩,可吹牛的內(nèi)容都是我干的捺宗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼川蒙,長吁一口氣:“原來是場噩夢啊……” “哼蚜厉!你這毒婦竟也來了?” 一聲冷哼從身側響起畜眨,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昼牛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后康聂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰健,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年恬汁,在試婚紗的時候發(fā)現(xiàn)自己被綠了伶椿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡氓侧,死狀恐怖脊另,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情约巷,我是刑警寧澤偎痛,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站独郎,受9級特大地震影響踩麦,放射性物質發(fā)生泄漏枚赡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一靖榕、第九天 我趴在偏房一處隱蔽的房頂上張望标锄。 院中可真熱鬧,春花似錦茁计、人聲如沸料皇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽践剂。三九已至,卻和暖如春娜膘,著一層夾襖步出監(jiān)牢的瞬間逊脯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工竣贪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留军洼,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓演怎,卻偏偏與公主長得像匕争,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爷耀,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355