關(guān)于sql優(yōu)化

在業(yè)務(wù)快速開發(fā)迭代中,其實(shí)很多性能的瓶頸在于我們底層的數(shù)據(jù)庫(kù),sql語(yǔ)句的性能,索引創(chuàng)建的時(shí)機(jī),間接就決定著我們請(qǐng)求響應(yīng)時(shí)間。

sql之所以要優(yōu)化是因?yàn)橛写罅康穆樵兇嬖?,可以利用show variables like 'slow_query_log'來查看是否開啟慢查詢,以及慢查詢的閾值設(shè)置根據(jù)自己的業(yè)務(wù)開發(fā)需要而做修改,那慢查詢產(chǎn)生的原因有以下幾點(diǎn):

1.兩張比較大的表進(jìn)行 JOIN,但是沒有給表的相應(yīng)字段加索引,這個(gè)是最常見的慢sql出現(xiàn)的原因

2.表存在索引,但是查詢的條件過多,且字段順序與索引順序不一致

這里就要說到聯(lián)合索引,要滿足最左前綴匹配原則,mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整;

3.對(duì)很多查詢結(jié)果進(jìn)行 GROUP BY

Group By 關(guān)鍵字由于涉及到數(shù)據(jù)的排序,對(duì)于數(shù)據(jù)量特別大的情況,還需要進(jìn)行外排序。所以,盡量對(duì)小數(shù)據(jù)量進(jìn)行 Group By 操作;group by 盡量對(duì)少的數(shù)據(jù)量使用 前面加where 過濾后使用,提前規(guī)劃好數(shù)據(jù)庫(kù)設(shè)計(jì)避免大數(shù)據(jù)量group by,可以考慮能不能把group by后面的緯度一開始分表存儲(chǔ)


下面是在學(xué)習(xí)工作之中遇到的實(shí)際問題

場(chǎng)景1:? ?

在 90 萬(wàn)條的數(shù)據(jù)表中,大概在 30 個(gè)字段左右,字段都是 int 和 char 類型。其中一個(gè)字段 name 的值有 a、b、c、d 四種。給 name 創(chuàng)建了普通索引。

SELECT * FROM hotel WHERE name IN('a','b');

此時(shí)利用explain關(guān)鍵字進(jìn)行sql性能分析發(fā)現(xiàn)type是ALL,說明進(jìn)行性能比較差的全表掃描,并沒有走索引,Extra是Using where,說明就算用了索引后,還要進(jìn)行回表操作,可以會(huì)造成不必要的IO操作


索引完全沒有起到任何作用。如何優(yōu)化索引?

其實(shí)這里并不是因?yàn)閿?shù)據(jù)量少而不走索引,而是索引本身建立的不正確,name字段本身的唯一性并不高,我們?cè)诶斫馑饕举|(zhì)之后假設(shè)走了索引,并且假設(shè)一個(gè)極端的情況,90萬(wàn)數(shù)據(jù),name字段有0,1兩個(gè)值,利用索引先要讀索引文件,然后利用二分查找或者b+數(shù)分叉查找,找到對(duì)應(yīng)的數(shù)據(jù)磁盤指針,再通過指針讀取磁盤上的數(shù)據(jù)(如果是非聚集索引,還要進(jìn)行多級(jí)索引讀?。?,影響的結(jié)果集是45萬(wàn)(二分查找的情況),那在這種情況下,索引查找步驟繁瑣,甚至不如全表掃描的速度快。

所以說,當(dāng)name字段唯一性不高時(shí),in中的數(shù)據(jù)過多時(shí),將不會(huì)走索引。

場(chǎng)景2:

比較經(jīng)典的例子是在mysql中l(wèi)imit可以實(shí)現(xiàn)快速分頁(yè),但是如果數(shù)據(jù)到了幾百萬(wàn)時(shí)我們的limit必須優(yōu)化才能有效的合理的實(shí)現(xiàn)分頁(yè)了,否則可能卡死你的服務(wù)器。

select * from table limit 0, 10 ,這個(gè)是沒有問題的,如果select id,name,content from users order by id limit 100000,20,這條語(yǔ)句掃描100020行,但只要20行,問題就出在這里了,首先可以這樣優(yōu)化,如果記錄了上次的最大ID

利用select id,name,content from users where id>100073 order by id asc limit 20,掃描20行


再比如 select * from table where name=’f’ order by id limit 300000,10 執(zhí)行時(shí)間是 3.21s? ?優(yōu)化后的sql:

? ? ? ? ? ? ?select * from (

? ? ? ? ? ? ? ?select id from table

? ? ? ? ? ? ? ?where byname=’f’ order by id limit 300000,10

? ?) a

? ?left join table b on a.id=b.id。執(zhí)行時(shí)間為 0.11s 速度明顯提升

? ?這里需要說明的是 我這里用到的字段是 name ,id 需要把這兩個(gè)字段做復(fù)合索引,否則的話效果提升不明顯。

? ?當(dāng)一個(gè)數(shù)據(jù)庫(kù)表過于龐大,LIMIT offset, length中的offset值過大,則SQL查詢語(yǔ)句會(huì)非常緩慢,你需增加order by,并且order by字段需要建立索引。

? ?如果使用子查詢?nèi)?yōu)化LIMIT的話,則子查詢必須是連續(xù)的,某種意義來講,子查詢不應(yīng)該有where條件,where會(huì)過濾數(shù)據(jù),使數(shù)據(jù)失去連續(xù)性。

? ?如果你查詢的記錄比較大,并且數(shù)據(jù)傳輸量比較大,比如包含了text類型的field,則可以通過建立子查詢。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 50個(gè)常用的sql語(yǔ)句Student(S#,Sname,Sage,Ssex) 學(xué)生表Course(C#,Cname...
    哈哈海閱讀 1,334評(píng)論 0 7
  • 一、MySQL優(yōu)化 MySQL優(yōu)化從哪些方面入手: (1)存儲(chǔ)層(數(shù)據(jù)) 構(gòu)建良好的數(shù)據(jù)結(jié)構(gòu)??梢源蟠蟮奶嵘覀僑...
    寵辱不驚丶?xì)q月靜好閱讀 2,654評(píng)論 1 8
  • SQL 優(yōu)化(載錄于:http://m.jb51.net/article/5051.htm) 作者: (一)深入淺...
    yuantao123434閱讀 811評(píng)論 0 7
  • MSSQL 跨庫(kù)查詢(臭要飯的!黑夜) 榨干MS SQL最后一滴血 SQL語(yǔ)句參考及記錄集對(duì)象詳解 關(guān)于SQL S...
    碧海生曲閱讀 5,909評(píng)論 0 1
  • 理論塢——打造你自己的理論庫(kù) 蝴蝶效應(yīng)(The Butterfly Effect)是指在一個(gè)動(dòng)力系統(tǒng)中,初始條件下...
    雨相三千閱讀 485評(píng)論 0 2

友情鏈接更多精彩內(nèi)容