關於數據庫SQL調優

數據庫優化

高效使用索引

儘可能避免全表掃描

減少無效數據的查詢

索引創建規則

idx_表名_字段名(字段名可以是多個,eg. idx_table_name,idx_table_nameAge)

Mysql所認爲的執行順序

FROM <left_table>

ON  <join_condition>

<join_type>JOIN <right_table>

WHERE <where_condition>

GROUP BY <group_by_list>

HAVING <having_codition>

SELECT

DISTINCT <select_list>

ORDER BY <order_by_condition>

LIMIT <limit_number>

哪些情況需要建索引

1.主鍵自動建立唯一索引

2.頻繁作爲查詢條件的字段應該創建索引

3.查詢中與其他表關聯的字段

4.where條件裏用不到的字段不創建索引

5.統計分組排序字段

哪些情況不需要建索引

1.表記錄太少(百萬以下不用考慮建索引,一般數據夠300萬就要建索引)

2.頻繁更新的字段不適合建索引 

3.數據重複且分佈平均的字段不建索引,比如性別,不是男就是女。索引是區別越大,效率越高

SQL優化

1.生產上出現慢SQL,首先要做的就是復現

2.設置閾值,開啓慢日誌查詢(慢日誌影響性能,生產上一定要關閉。比如超過5秒就是慢查詢要這麼抓出來)

3.explain + 慢日誌分析

4.show profile分析(本地Navicat就可以看到,生產上只能用命令)

5.專業人士進行SQL服務器參數調優

Explain

首先要知道explain有哪些信息。id,select_type,table,partitions,type,possible_keys,key,key_len,ref,rows,filtered,Extra這些是基本的,還有些後來加的

id

id是用來表示執行順序的東西。id相同就按順序執行,id不同值越大;優先級越高,越先執行

一般出現id不同就是有子查詢

select_type

就是select查詢的類型

SIMPLE 

最簡單的查詢語句,不包含子查詢或union

PRIMARY

當查詢語句中包含任何複雜的子部分,最外層查詢則被標記爲PRIMARY

SUBQUERY

當select或where列表中包含了子查詢,該子查詢被標記爲SUBQUERY

DERIVED

表示包含在from子句中的子查詢的select,在我們的from列表中的包含的子查詢會被標記爲DERIVED

UNION

如果union後邊又出現的select語句,則會被標記爲union;若union包含在from子句的子查詢中。外層select被標記爲DERIVED

UNION RESULT

代表從union的臨時表中讀取的數據,table列的<union1,3>表示用第一個結果和第三個select的結果進行union操作

table

並不一定是真實的表,有別名,也有臨時表

partitions

查詢時匹配到的分區信息,對於非分區表值爲NULL,查詢的是分區表時,partitions顯示分區表命中的分區情況

type

system>const>eq_ref>ref>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>All

system就是表中只有一行記錄,相當於系統表,不需要磁盤IO,速度非常快

const表示查詢時命中primary key主鍵或unique唯一索引,或者被連接的部分是一個常量const值,查詢速度非常快

eq_ref對於每一個索引,表中只有一條記錄與之匹配

ref返回匹配某個單獨值的所用行,也算是一種索引訪問

ref_or_null類似於ref,會額外搜索null的行

index_merge使用了索引合併,查詢使用了兩個以上的方法

unique_subquery該類型替換了下面形式的IN子查詢的ref:value IN (SELECT primary_key FROM single_table WHERE some_expr),返回不重複值

index_subquery和unique_subquery類似,返回重複值

range使用索引檢索範圍內的行betwee,>,<,in

index遍歷索引樹,也很慢但比All強

All全表掃描,性能最差但驅動表避免不了

possible_keys

可能使用到的索引,如果是覆蓋索引,他可以爲null

key

實際用到的索引,使用到則標記出索引,沒有使用到則爲NULL

key_len

越短當然越好,越長就越精準。需要注意的是key_len只計算where條件中用到的索引長度,而排序和分組即便用到了索引也不會計算到key_len中

ref

常見的有null,func,const,字段名

使用常量等值查詢,顯示const

當關聯查詢時,會顯示相應關聯表的關聯字段

如果查詢條件使用了表達式,函數或者內部隱式轉換可能顯示爲func

其他情況爲null

rows

rows以表的統計信息和索引使用情況,計算需要讀取多少行,rows越小代表掃描的行數越少

filtered

代表表中符合條件的記錄數

Extra

一些重要的額外信息

using filesort,部分使用到了索引,一般是order by的字段沒有索引,需要優化

using temporary,使用中間表保存中間結果,一般和group by,order by沒用到索引,需要優化

using index,使用到了覆蓋索引,使用了覆蓋索引,覆蓋索引就是索引列和查詢列一致,順序不同無所謂。這樣就不需要查詢數據行直接查索引就好,推薦使用

using where,查詢時未找到可用索引,進而通過where條件過濾獲取

using join buffer,在我們連表查詢如果連接條件沒有用到索引,需要一個連接緩衝區來存儲中間結果,join太多了,可以考慮加索引或調大join buffer的參數

impossible where ,where後面的條件不正確

No tables used ,沒有表或者用了虛表

單表優化

1.最左前綴匹配法則

2.不在索引列上做任何操作(計算,函數,顯式或者隱式轉換)

3.範圍條件in,>,<等索引會失效,考慮把範圍放最後或者使用between

4.儘量使用覆蓋索引,不使用select *

5.使用!=或<>無法使用索引,這個看版本高版本的都是range,低版本建議不要在相關字段上設置索引

6.is null,is not null不走索引

7.like只有用 xx%可以走索引,這個也看版本的,數據實在過大(過億了這種)考慮走搜索引擎Es,Solr。如果數據量很少剛剛幾千條別想了直接%xx%。如果數據量也不算小,建議使用內置函數INSTR(str,substr)

8.字符串不加單引號不走索引,MySQL會幫你隱式轉換但是不走索引

9.or使索引失效,低版本會,高版本肯定不會失效

10.拼裝where後的條件少用1=1,在mybatis用where標籤,好多項目都用這個,不用的也有類似解決方案

11.極端情況下,可以考慮使用hint(ignore index,force index加在from後面)優化語句。所謂極端可以是某個語句他不走索引了,查詢慢到開花,強制讓他走索引,留時間出來分析語句。這個慎用,搞不好會影響到其他業務,數據庫版本升級也會對他造成很大打擊

12.別用select *,不可能一張表裏所有字段都是索引的

13.能用where,不用having,因爲where能提前篩選出來,就會少很多數據

多表優化

LEFT JOIN索引加在從(右)表的關聯字段上,RIGHT JOIN索引加在主(左)表的關聯字段上,爲什麼這麼說呢?就比如說左連接會把主(左)表的所有關聯數據都拿去做匹配。如果索引加在主(左)表就會導致要掃描一些沒必要查的行,導致效率下降,右連接也是同理。但還是要以小表驅動大表,不然得出來的結果還是有很大差距的

阿里手冊開發手冊也提過join的次數最好不要超過三次,超過了非常影響效率(想起我以前寫SQL,5表查詢我寫了5個left join我還很自豪.....),關於這個我有兩種解決方案:1.根據業務在表中設計冗餘字段,你想要的某個字段已經存好放在同一張表裏了,那就不需要聯表了 2.設計中間表,中間表只存其他表對應記錄的id,做業務時順便往中間表裏插入其他表的id確保他的id不會爲空,讓需要多次JOIN的表跟中間表關聯上,這樣可以根據中間表id查出中間表上的其他表的id字段,再根據各個id字段查出所需要的對應信息,也就是說分兩步走

索引生效圖鑑

我們的索引長這樣idx_abc(a,b,c),是個複合索引,一般實際使用都是用的複合索引


慢日誌分析

使用慢日誌的分析工具mysqldumpslow

以下是幾條用的較多的命令

得到返回記錄集最多的10條SQL

mysqldumpslow -s -r -t 10 慢日誌地址具體到文件(/var/lib/mysql/slow.log)| more

得到訪問次數最多的10條SQL

mysqldumpslow -s c -t 10 慢日誌地址具體到文件 | more

得到按照時間排序的前10條裏面包含有左連接的SQL

mysqldumpslow -s t -t 10 -g "left join" 慢日誌地址具體到文件 | more

show profile

其實只要注意幾個點就好了

converting to HEAP to MyISAM 查詢結果太大,內存不夠用往磁盤上搬

creating tmp table 創建臨時表,拷貝數據到臨時表用完了再刪除,這個非常的影響效率

copying to tmp table on disk 把內存中臨時表複製磁盤,這個就是必須要優化了

locked 鎖表了,這個要看是爲什麼鎖,衆所周知DML加了各種鎖,鎖了正常那就不用管,不正常就看是不是常用的業務,不是常用的kill,常用的看看是kill好還是等到滿足解鎖條件自動解鎖好

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章