數據庫優化
高效使用索引
儘可能避免全表掃描
減少無效數據的查詢
索引創建規則
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好還是等到滿足解鎖條件自動解鎖好