{eval=Array;=+count(Array);}
視圖的方式可以“簡(jiǎn)化”查詢(xún)邏輯,讓查詢(xún)看起來(lái)簡(jiǎn)單,但是如果多表查詢(xún)性能差,對(duì)于視圖的方式來(lái)說(shuō),要排查性能瓶頸還是比較困難的。所以?xún)?yōu)化的本質(zhì)不會(huì)變,是基于資源的平衡,簡(jiǎn)化不能夠解決性能問(wèn)題。
加視圖,最后還是查的這幾張表,最好的就是將你需要的數(shù)據(jù),通過(guò)代碼的方式轉(zhuǎn)的一張表里面,然后單表操作是最快的,對(duì)單表加索引,千萬(wàn)數(shù)據(jù)也能查的很快,如果數(shù)據(jù)量還是很大,還可以做成分區(qū),針對(duì)分區(qū)去查,檢索速度也會(huì)很快
問(wèn)題
我們有一個(gè) SQL,用于找到?jīng)]有主鍵 / 唯一鍵的表,但是在 MySQL 5.7 上運(yùn)行特別慢,怎么辦?
實(shí)驗(yàn)
我們搭建一個(gè) MySQL 5.7 的環(huán)境,此處省略搭建步驟。
寫(xiě)個(gè)簡(jiǎn)單的腳本,制造一批帶主鍵和不帶主鍵的表:
執(zhí)行一下腳本:
現(xiàn)在執(zhí)行以下 SQL 看看效果:
...
執(zhí)行了 16.80s,感覺(jué)是非常慢了。
現(xiàn)在用一下 DBA 三板斧,看看執(zhí)行計(jì)劃:
感覺(jué)有點(diǎn)慘,由于 information_schema.columns 是元數(shù)據(jù)表,沒(méi)有必要的統(tǒng)計(jì)信息。
那我們來(lái) show warnings 看看 MySQL 改寫(xiě)后的 SQL:
我們格式化一下 SQL:
可以看到 MySQL 將
select from A where A.x not in (select x from B) //非關(guān)聯(lián)子查詢(xún)
轉(zhuǎn)換成了
select from A where not exists (select 1 from B where B.x = a.x) //關(guān)聯(lián)子查詢(xún)
如果我們自己是 MySQL,在執(zhí)行非關(guān)聯(lián)子查詢(xún)時(shí),可以使用很簡(jiǎn)單的策略:
select from A where A.x not in (select x from B where ...) //非關(guān)聯(lián)子查詢(xún):1. 掃描 B 表中的所有記錄,找到滿(mǎn)足條件的記錄,存放在臨時(shí)表 C 中,建好索引2. 掃描 A 表中的記錄,與臨時(shí)表 C 中的記錄進(jìn)行比對(duì),直接在索引里比對(duì),
而關(guān)聯(lián)子查詢(xún)就需要循環(huán)迭代:
select from A where not exists (select 1 from B where B.x = a.x and ...) //關(guān)聯(lián)子查詢(xún)掃描 A 表的每一條記錄 rA: 掃描 B 表,找到其中的第一條滿(mǎn)足 rA 條件的記錄。
顯然,關(guān)聯(lián)子查詢(xún)的掃描成本會(huì)高于非關(guān)聯(lián)子查詢(xún)。
我們希望 MySQL 能先"緩存"子查詢(xún)的結(jié)果(緩存這一步叫物化,MATERIALIZATION),但MySQL 認(rèn)為不緩存更快,我們就需要給予 MySQL 一定指導(dǎo)。
...
可以看到執(zhí)行時(shí)間變成了 0.67s。
整理
我們?cè)\斷的關(guān)鍵點(diǎn)如下:
1. 對(duì)于 information_schema 中的元數(shù)據(jù)表,執(zhí)行計(jì)劃不能提供有效信息。
2. 通過(guò)查看 MySQL 改寫(xiě)后的 SQL,我們猜測(cè)了優(yōu)化器發(fā)生了誤判。
3. 我們?cè)黾恿?hint,指導(dǎo) MySQL 正確進(jìn)行優(yōu)化判斷。
但目前我們的實(shí)驗(yàn)僅限于猜測(cè),猜中了萬(wàn)事大吉,猜不中就無(wú)法做出好的診斷。
0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答