【MySQL】性能优化之 straight_join
生活随笔
收集整理的這篇文章主要介紹了
【MySQL】性能优化之 straight_join
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? ?研究過(guò)或者熟悉oracle性能調(diào)優(yōu)的朋友都知道oracle 提供很多hint 指定from 后的表的連接順序,如use_hash ?ordered ,leading 等,而MySQL 對(duì)表的連接只支持 nested loop Join, 提供的表連接驅(qū)動(dòng)的hint 只有--straight_join(相當(dāng)于Oracle里面的use_nl).其語(yǔ)法如下: ? select ..from ?tab1 ?straiht_join ?tab2 where ... straight_join 實(shí)際上與內(nèi)連接 inner join 表現(xiàn)完全一致,不同的是使用了 straight_join 后,tab1 會(huì)先于 tab2 載入。 ? ?MySQL 在執(zhí)行 inner join 的時(shí)候,會(huì)根據(jù)自己內(nèi)部的優(yōu)化規(guī)則來(lái)決定先載入 tab1 還是 tab2,如果您確認(rèn) MySQL 載入表的順序并不是最優(yōu)化的時(shí)候,就可以使用 straight_join 以替代 inner join,來(lái)強(qiáng)制MySQL 選擇指定的執(zhí)行順序。 【現(xiàn)象】 生產(chǎn)環(huán)境中遇到一個(gè)例子,執(zhí)行sql需要1.29s 已經(jīng)超出業(yè)務(wù)方的要求,需要進(jìn)行優(yōu)化,sql 如下
select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size from ?user u, instance d , image m where d.region_no = 'cn-cm9002' and ? ? ? ?u.user_id = d.user_id and ? ? ? ?d.image_id = m.image_id and ? ? ? ?d.status != 8 and? ? ? ? ?d.gmt_create <'2013-08-19 14:00:00';
hy@3309 03:09:09>explain select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size ? ? -> from ?user u, instance d , image m ? ? -> where d.region_no = 'cn-cm9002' and ? ? -> ? ? ? ?u.user_id = d.user_id and ? ? -> ? ? ? ?d.image_id = m.image_id and ? ? -> ? ? ? ?d.status != 8 and? ? ? -> ? ? ? ?d.gmt_create <'2013-08-19 14:00:00'; +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ | id | select_type | table | type ? | possible_keys ? ? ? ? ? ? ? ? ? ? ? | key ? ? ? ? ? ? ? ?| key_len | ref ? ? ? ? ? ? ?| rows ? | Extra ? ? ? | +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ | ?1 | SIMPLE ? ? ?| u ? ? | index ?| PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | idkp ? ? ? ?| 98 ? ? ?| NULL ? ? ? ? ? ? | 133002 | Using index | | ?1 | SIMPLE ? ? ?| d ? ? | ref ? ?| image_id,ind_i_uid_hostname,user_id | ind_i_uid_hostname | 4 ? ? ? | hy.u.user_id ?| ? ? ?1 | Using where | | ?1 | SIMPLE ? ? ?| m ? ? | eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY ? ? ? ? ? ?| 4 ? ? ? | hy.d.image_id | ? ? ?1 | ? ? ? ? ? ? | +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ 3 rows in set (0.00 sec)
【解決方法】 使用 straight_join 方式優(yōu)化sql 執(zhí)行的順序 結(jié)果如下: rac1@3309 15:01:55>explain select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size ? ? -> ? ? ? from instance d straight_join ?user u on u.user_id = d.user_id, ?image m ? ? -> ? ? ? where d.region_no = 'cn-cm9002' and ? ? -> ? ? ? ? ? ? d.image_id = m.image_id and ? ? -> ? ? ? ? ? ? d.status != 8 and? ? ? -> ? ? ? ? ? ? d.gmt_create <'2013-08-19 14:00:00'; +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ | id | select_type | table | type ? | possible_keys ? ? ? ? ? ? ? ? ? ? ? | key ? ? | key_len | ref ? ? ? ? ? ? ?| rows ? | Extra ? ? ? | +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ | ?1 | SIMPLE ? ? ?| d ? ? | ALL ? ?| image_id,ind_i_uid_hostname,user_id | NULL ? ?| NULL ? ?| NULL ? ? ? ? ? ? | 316473 | Using where | | ?1 | SIMPLE ? ? ?| m ? ?| eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY | 4 ? ? ? | hy.d.image_id | ? ? ?1 | ? ? ? ? ? ? | | ?1 | SIMPLE ? ? ?| u ? ? | eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY | 4 ? ? ? | hy.d.user_id ?| ? ? ?1 | ? ? ? ? ? ? | +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ 3 rows in set (0.00 sec)
新的sql執(zhí)行結(jié)果: ?
【問(wèn)題分析】 上面的介紹中描述mysql的優(yōu)化器只支持 nest loop ,對(duì)于多表連接會(huì)mysql優(yōu)化器采用了簡(jiǎn)單的方式:選擇結(jié)果集小的表作為驅(qū)動(dòng)表。 instance表連接 user表有兩種連接方式: A 選擇user 表作為驅(qū)動(dòng)表 優(yōu)化器掃描133002行 B 選擇instance表作為驅(qū)動(dòng)表 優(yōu)化器掃描 ?316473行
因此 優(yōu)化器選擇了看起來(lái)正確的執(zhí)行計(jì)劃 以u(píng)ser表作為驅(qū)動(dòng)表。但是 我們查看where條件,正確的應(yīng)該是 通過(guò)instance 的region_no,status ,gmt_create 過(guò)濾得到instance的結(jié)果集,再來(lái)和user,image中的表進(jìn)行關(guān)聯(lián)。 而執(zhí)行計(jì)劃是掃描user表中全部的記錄再去關(guān)聯(lián)instance 表和image表,顯然執(zhí)行順序有 偏差。因此加上straight_join hint 之后,強(qiáng)制優(yōu)化器選擇 instance為驅(qū)動(dòng)表,按照正確的執(zhí)行計(jì)劃執(zhí)行。 ? 附上表的記錄數(shù): hy@3309 01:11:17> select count(*) from user; +----------+ | count(*) | +----------+ | ? 134221 | +----------+ 1 row in set (0.02 sec)
hy@3309 01:19:44> select count(*) from instance; +----------+ | count(*) | +----------+ | ? 375732 | +----------+ 1 row in set (0.06 sec)
hy@3309 01:19:54> select count(*) from image; ?? +----------+ | count(*) | +----------+ | ? ?18858 | +----------+ 1 row in set (0.00 sec)
select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size from ?user u, instance d , image m where d.region_no = 'cn-cm9002' and ? ? ? ?u.user_id = d.user_id and ? ? ? ?d.image_id = m.image_id and ? ? ? ?d.status != 8 and? ? ? ? ?d.gmt_create <'2013-08-19 14:00:00';
hy@3309 03:09:09>explain select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size ? ? -> from ?user u, instance d , image m ? ? -> where d.region_no = 'cn-cm9002' and ? ? -> ? ? ? ?u.user_id = d.user_id and ? ? -> ? ? ? ?d.image_id = m.image_id and ? ? -> ? ? ? ?d.status != 8 and? ? ? -> ? ? ? ?d.gmt_create <'2013-08-19 14:00:00'; +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ | id | select_type | table | type ? | possible_keys ? ? ? ? ? ? ? ? ? ? ? | key ? ? ? ? ? ? ? ?| key_len | ref ? ? ? ? ? ? ?| rows ? | Extra ? ? ? | +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ | ?1 | SIMPLE ? ? ?| u ? ? | index ?| PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | idkp ? ? ? ?| 98 ? ? ?| NULL ? ? ? ? ? ? | 133002 | Using index | | ?1 | SIMPLE ? ? ?| d ? ? | ref ? ?| image_id,ind_i_uid_hostname,user_id | ind_i_uid_hostname | 4 ? ? ? | hy.u.user_id ?| ? ? ?1 | Using where | | ?1 | SIMPLE ? ? ?| m ? ? | eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY ? ? ? ? ? ?| 4 ? ? ? | hy.d.image_id | ? ? ?1 | ? ? ? ? ? ? | +----+-------------+-------+--------+-------------------------------------+--------------------+---------+------------------+--------+-------------+ 3 rows in set (0.00 sec)
【解決方法】 使用 straight_join 方式優(yōu)化sql 執(zhí)行的順序 結(jié)果如下: rac1@3309 15:01:55>explain select ?d.instance_no,d.zone_id, d.region_no,d.user_id,d.cores,d.mem,d.disk, d.tx_pub , u.idkp , m.image_no, m.platform, m.image_size ? ? -> ? ? ? from instance d straight_join ?user u on u.user_id = d.user_id, ?image m ? ? -> ? ? ? where d.region_no = 'cn-cm9002' and ? ? -> ? ? ? ? ? ? d.image_id = m.image_id and ? ? -> ? ? ? ? ? ? d.status != 8 and? ? ? -> ? ? ? ? ? ? d.gmt_create <'2013-08-19 14:00:00'; +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ | id | select_type | table | type ? | possible_keys ? ? ? ? ? ? ? ? ? ? ? | key ? ? | key_len | ref ? ? ? ? ? ? ?| rows ? | Extra ? ? ? | +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ | ?1 | SIMPLE ? ? ?| d ? ? | ALL ? ?| image_id,ind_i_uid_hostname,user_id | NULL ? ?| NULL ? ?| NULL ? ? ? ? ? ? | 316473 | Using where | | ?1 | SIMPLE ? ? ?| m ? ?| eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY | 4 ? ? ? | hy.d.image_id | ? ? ?1 | ? ? ? ? ? ? | | ?1 | SIMPLE ? ? ?| u ? ? | eq_ref | PRIMARY ? ? ? ? ? ? ? ? ? ? ? ? ? ? | PRIMARY | 4 ? ? ? | hy.d.user_id ?| ? ? ?1 | ? ? ? ? ? ? | +----+-------------+-------+--------+-------------------------------------+---------+---------+------------------+--------+-------------+ 3 rows in set (0.00 sec)
新的sql執(zhí)行結(jié)果: ?
【問(wèn)題分析】 上面的介紹中描述mysql的優(yōu)化器只支持 nest loop ,對(duì)于多表連接會(huì)mysql優(yōu)化器采用了簡(jiǎn)單的方式:選擇結(jié)果集小的表作為驅(qū)動(dòng)表。 instance表連接 user表有兩種連接方式: A 選擇user 表作為驅(qū)動(dòng)表 優(yōu)化器掃描133002行 B 選擇instance表作為驅(qū)動(dòng)表 優(yōu)化器掃描 ?316473行
因此 優(yōu)化器選擇了看起來(lái)正確的執(zhí)行計(jì)劃 以u(píng)ser表作為驅(qū)動(dòng)表。但是 我們查看where條件,正確的應(yīng)該是 通過(guò)instance 的region_no,status ,gmt_create 過(guò)濾得到instance的結(jié)果集,再來(lái)和user,image中的表進(jìn)行關(guān)聯(lián)。 而執(zhí)行計(jì)劃是掃描user表中全部的記錄再去關(guān)聯(lián)instance 表和image表,顯然執(zhí)行順序有 偏差。因此加上straight_join hint 之后,強(qiáng)制優(yōu)化器選擇 instance為驅(qū)動(dòng)表,按照正確的執(zhí)行計(jì)劃執(zhí)行。 ? 附上表的記錄數(shù): hy@3309 01:11:17> select count(*) from user; +----------+ | count(*) | +----------+ | ? 134221 | +----------+ 1 row in set (0.02 sec)
hy@3309 01:19:44> select count(*) from instance; +----------+ | count(*) | +----------+ | ? 375732 | +----------+ 1 row in set (0.06 sec)
hy@3309 01:19:54> select count(*) from image; ?? +----------+ | count(*) | +----------+ | ? ?18858 | +----------+ 1 row in set (0.00 sec)
總結(jié)
以上是生活随笔為你收集整理的【MySQL】性能优化之 straight_join的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: myeclipse无法启动tomcat的
- 下一篇: 解决Nginx与mysql勾结的错误