目錄
1.sql語句編寫
2.explain 工具的使用--重點(diǎn)
1.sql語句編寫
SQL編寫
1.執(zhí)行大的delete、update、insert操作要慎重,特別是對業(yè)務(wù)繁忙的系統(tǒng),要盡量避免對線上業(yè)務(wù)產(chǎn)生影響。
解決辦法是:大操作切割為小操作,使用limit子句限制每次操作的記錄數(shù),也可以利用一些日期字段基于更小粒度的時間范圍進(jìn)行操作。
2.避免使用select * 語句,select語句之用于獲取需要的字段。
3.使用預(yù)編譯語句,可以提高性能并且防范 sql注入 攻擊。
4.一般情況下update,delete 語句中不要使用limit。
5.where 條件語句中必須使用合適的類型,避免mysql進(jìn)行隱式轉(zhuǎn)換。
6.insert into 必須顯式指明字段名稱,不要使用insert into table()。
7.避免在sql 語句中進(jìn)行數(shù)學(xué)運(yùn)算或函數(shù)運(yùn)算,避免將業(yè)務(wù)邏輯和數(shù)據(jù)存儲耦合在一起。
8.insert 語句如果使用批量提交,如insert into table values(),()...那么values 的個數(shù)不應(yīng)過多。一次性提交過多記錄,會導(dǎo)致I/O緊張,出現(xiàn)慢查詢。
9.避免使用存儲過程、觸發(fā)器、函數(shù)等,這些特性會將業(yè)務(wù)邏輯與數(shù)據(jù)庫耦合在一起,并且MySQL的存儲過程,觸發(fā)器,函數(shù)中可能存在bug。
10.盡量避免使用子查詢,連接。盡量將子查詢轉(zhuǎn)化為連接查詢,mysql 查詢優(yōu)化器會優(yōu)化連接查詢,但連接的表要盡可能的少,如果很多,可以考慮反范式設(shè)計(jì)。即對設(shè)計(jì)階段做一些改造。
11.使用合理的sql語句以減少與數(shù)據(jù)庫的交互次數(shù)。
12.建議使用合理的分頁技術(shù)以提高操作效率。
2.explain 工具的使用
explain工具的作用
1.使用 explain 工具可以確認(rèn)執(zhí)行計(jì)劃是否良好,查詢是否走了合理的索引。
2.不同版本MySQL 優(yōu)化器各有不同,一些優(yōu)化規(guī)則隨著版本的發(fā)展可能有變化,
查詢的執(zhí)行計(jì)劃隨著數(shù)據(jù)的變化也可能發(fā)生變化,這類情況就需要使用explain 來驗(yàn)證自己的判斷。
explain 工具實(shí)操
執(zhí)行如下腳本,觀察控制臺輸出
explain select name from test where id = 32;
注意數(shù)據(jù)表使用如下腳本:
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8;
table name = test、column1 = id、column2 = name.
執(zhí)行結(jié)果如下所示:
下面詳細(xì)闡述explain 輸出的各項(xiàng)內(nèi)容:
id:
包含一組數(shù)字,表示查詢中執(zhí)行 select子句 或操作表的順序。
如果 id 相同,則執(zhí)行順序由上到下。
select_type:
表示查詢中每個 select 子句的類型(是簡單還是復(fù)雜)輸出結(jié)果類似如下:
1.simple
查詢中不包含子查詢或者union
2.primary
查詢中若包含任何復(fù)雜子查詢,最外層查詢被標(biāo)記為primary
3.subquery
在select 或 where 列表中包含了子查詢,則該查詢被標(biāo)記為subquery
4.derived
在from列表中包含的子查詢被標(biāo)記為derived(衍生)
5.union
若第二個select出現(xiàn)在union之后,則被標(biāo)記為derived。
6.union result
從union表中獲取結(jié)果的select將被標(biāo)記為 union result。
select_type 只需要了解分類即可,這個信息并不是最有價(jià)值的。
type:最有價(jià)值信息之一
type表示 MySQL 在表中找到所需行的方式,又稱為“訪問類型”,常見的類型如下所示:
all、index、range、ref、eq_ref、const,system,null
以上類型,由左至右,由最差到最好。
all: Full Table Scan,MySQL 將遍歷全表以找到匹配的行。
index:Full Index Scan,index 與 all 區(qū)別為index類型只遍歷索引樹。假設(shè)表中有主鍵字段id,則select id from table_name;type即為Full Index Scan。
range:索引掃描范圍,對索引的掃描開始于某一點(diǎn),返回匹配的域或行,常見于between、<、>等的查詢。
ref:非唯一性索引掃描,將返回匹配某個單獨(dú)值得所有行。常見于使用非唯一索引或唯一索引的非唯一前綴的查找。
eq_ref:唯一性索引掃描,對于每個索引鍵表中只有一條記錄與之匹配。常見于主鍵或唯一索引掃描。
const、system:當(dāng)MySQL對查詢的某部分進(jìn)行優(yōu)化,并轉(zhuǎn)化為一個常量時,可使用這些類型進(jìn)行訪問。如果主鍵置于where列表中,MySQL就能將該查詢轉(zhuǎn)換為一個常量,system是const
的一個特例,當(dāng)查詢的表只有一行的情況下,即可使用system。
null:MySQL 在優(yōu)化過程中分解語句,執(zhí)行時甚至不用訪問表或索引,舉例如下:
explain select * from (select * from t1 where id = 1)d1;
possible_keys
possible_keys 將指出MySQL能使用哪個索引在表中找到行,查詢涉及的字段上若存在索引,則該索引將被列出,但不一定會被查詢使用。
key:最有價(jià)值信息之二
key 將顯示MySQL在查詢中實(shí)際使用到的索引,若沒有使用索引,則顯示為null。查詢中若使用到了覆蓋索引,則該索引僅僅出現(xiàn)在 key 列表中,possible_keys中并不顯示。
key_len
key_len表示索引中使用的字節(jié)數(shù),可通過該列計(jì)算查詢中使用的索引的長度。
ref
ref表示上述表的連接匹配條件,即哪些列或常亮被用于查找索引列上的值。
rows:最有價(jià)值信息之三
rows 表示MySQL根據(jù)表統(tǒng)計(jì)信息及索引選用的情況, 估算查找所需記錄需要讀取的行數(shù)。使用到索引一般情況下會使得rows的值降低。
Extra:最有價(jià)值信息之四
Extra 包含不適合在其他列中顯示但十分重要的額外信息。可能包如下4種信息。
1.Using index
該值表示相應(yīng)的select操作中使用到了覆蓋索引,包含滿足查詢需要的數(shù)據(jù)的索引稱為覆蓋索引。
2.Using where
如果查詢未能使用索引,則Using where 的作用只是提醒我們 MySQL 將用where 子句來過濾結(jié)果集。
3.Using temporary
表示MySQL需要使用臨時表來存儲結(jié)果集,常見于order by 與 group by,事實(shí)上group by會進(jìn)行隱式的order by。
如果我們在group by 時利用索引分組(其實(shí)包含排序的過程)排序,則可以提高性能,因?yàn)椴粫藭r查詢輸出里沒有了Using temporary,Using filesort。
4.Using filesort
Using filesort 即文件排序,MySQL 中將無法使用索引完成的排序操作,稱為文件排序。
上文篇幅有點(diǎn)長,但都是必須了解的概念。最有價(jià)值信息是我們判斷sql語句執(zhí)行是否高效的基準(zhǔn),了解四個最有價(jià)值信息是最重要的。
繼續(xù)演示explain的使用,使用上文的評判標(biāo)準(zhǔn)來看下語句的執(zhí)行效率:
1.主鍵查詢
上述為主鍵查詢的explain信息
type = const 效率很高
key = primary 實(shí)際使用的索引為主鍵
rows = 1 查找的記錄數(shù)為1
extra = null ,沒有任何額外信息
總體來說,性能是極高。
2.主鍵范圍查詢
上述為主鍵范圍查詢的explain信息
type =range 范圍查詢,效率不是最低
key = primary 實(shí)際使用的索引為主鍵
rows = 7 查找的記錄數(shù)為7
extra = Using where ,最終使用where 做結(jié)果集過濾,未使用到覆蓋索引。
總體來說,性能是很高。
3.未帶索引查詢
如上圖所示,name 并未做索引。
type =ALL Full Table Scan 全表查詢
key =NULL 未使用索引
rows = 7 10數(shù)據(jù)庫中所有記錄
extra = Using where ,最終使用where 做結(jié)果集過濾,未使用到覆蓋索引。
總體來說,性能極差。(這也是我司內(nèi)部deviceId接口出問題的終極原因)。
4.未帶索引的分組查詢
如上圖所示,name 并未做索引。
type =ALL Full Table Scan 全表查詢
key =NULL 未使用索引
rows = 7 10數(shù)據(jù)庫中所有記錄
extra = Using where ,最終使用where 做結(jié)果集過濾,未使用到覆蓋索引。并使用到了temporary,filesort 臨時表與文件查詢。
總體來說,性能極差。
5.帶索引的分組查詢
我們現(xiàn)在為4與3中 name 創(chuàng)建索引,再來看看分析結(jié)果
創(chuàng)建索引腳本如下
alter table test add index idx_name(name);
name 被索引之后的效果
再運(yùn)行3 和 4中的查詢語句
結(jié)果如下圖所示:
非分組帶索引查詢
type =ref 非唯一索引掃描,效率不是最低
key =name 實(shí)際使用的索引name索引(注意:idx_name與name都是在name字段上建立的索引)。
rows = 1 查找的記錄數(shù)為1
extra = Using index ,最終使用到覆蓋索引。
總體來說,查詢性能是極高的。
索引分組查詢
type =range 范圍掃描,效率不是最低
key =name 實(shí)際使用的索引name索引(注意:idx_name與name都是在name字段上建立的索引)。
rows = 1 查找的記錄數(shù)為1
extra = Using index ,最終使用where 做結(jié)果集過濾,使用到覆蓋索引。
總體來說,查詢性能是極高的。
當(dāng)然上述演示比較簡單,也不是非常具備實(shí)戰(zhàn)色彩,對于explain的使用,我們還應(yīng)在更多的數(shù)據(jù)庫操作場景中多多使用,這是sql調(diào)優(yōu)的利器。為我們后期的調(diào)優(yōu)減輕了負(fù)擔(dān),可以說如果在這一步做好了sql腳本的設(shè)計(jì),那么后期關(guān)于 sql調(diào)優(yōu) 問題會非常少。
關(guān)于公眾號
精進(jìn)!
道友們,你們好。早前個人就有開設(shè)公眾號的念想,今年10月終于開搞了。
我的個人的 訂閱號--T客來了;
平時自己會總結(jié)一些后端開發(fā)相關(guān)的技術(shù);
最近也迷上了音視頻開發(fā)相關(guān)技術(shù);
技術(shù)分享包括:
- 1.FFmpeg 工程實(shí)戰(zhàn)、
- 2.數(shù)據(jù)庫 MySQL原理與實(shí)戰(zhàn)、
- 3.Redis中間件、
- 4.Nginx、Java并發(fā)編程、
-
5.Go語言方面的技術(shù)知識與實(shí)操;
T客來了
微信掃碼就可以添加哦~
博客搬家:[大坤的個人博客]http://markfork.com/)
歡迎評論哦~