1.高并發(fā)優(yōu)化點(diǎn)有:
如果請求過多,判定web服務(wù)器的壓力過大,增加前端的web服務(wù)器,做負(fù)載均衡
如果請求靜態(tài)界面不卡了,但是動(dòng)態(tài)數(shù)據(jù)還是卡,說明MySQL處理的請求太多了,在應(yīng)用層增加緩存.
數(shù)據(jù)庫層其實(shí)是最脆弱的一層啡省,一般在應(yīng)用設(shè)計(jì)時(shí)在上游就需要把請求攔截掉娜睛,數(shù)據(jù)庫層只承擔(dān)“能力范圍內(nèi)”的訪問請求髓霞,所以,我們通過在服務(wù)層引入隊(duì)列和緩存畦戒,讓最底層的數(shù)據(jù)庫高枕無憂方库。但是如果請求激增,還是有大量的查詢壓力到MySQL,這個(gè)時(shí)候就要想辦法解決MySQL的瓶頸了。
2.mysql執(zhí)行流程:
大致可以分為以下步驟:
1.當(dāng)我們請求mysql服務(wù)器的時(shí)候,MySQL前端會有一個(gè)監(jiān)聽,請求到了之后,服務(wù)器得到相關(guān)的SQL語句,執(zhí)行之前(虛線部分為執(zhí)行),還會做權(quán)限的判斷
2.通過權(quán)限之后,SQL就到MySQL內(nèi)部,他會在查詢緩存中,看該SQL有沒有執(zhí)行過,如果有查詢過,則把緩存結(jié)果返回,說明在MySQL內(nèi)部,也有一個(gè)查詢緩存.但是這個(gè)查詢緩存,默認(rèn)是不開啟的,這個(gè)查詢緩存,和我們的Hibernate障斋,Mybatis的查詢緩存是一樣的,因?yàn)椴樵兙彺嬉骃QL和參數(shù)都要一樣,所以這個(gè)命中率是非常低的纵潦。
3.如果我們沒有開啟查詢緩存,或者緩存中沒有找到對應(yīng)的結(jié)果,那么就到了解析器,解析器主要對SQL語法進(jìn)行解析
4.解析結(jié)束后就變成一顆解析樹,這個(gè)解析樹其實(shí)在Hibernate里面也是有的,大家回憶一下,在以前做過Hibernate項(xiàng)目的時(shí)候,是不是有個(gè)一個(gè)antlr.jar。這個(gè)就是專門做語法解析的工具.因?yàn)樵贖ibernate里面有HQL垃环,它就是通過這個(gè)工具轉(zhuǎn)換成SQL的,我們編程語言之所以有很多規(guī)范邀层、語法,其實(shí)就是為了便于這個(gè)解析器解析,這個(gè)學(xué)過編譯原理的應(yīng)該知道.
5.得到解析樹之后,不能馬上執(zhí)行,這還需要對這棵樹進(jìn)行預(yù)處理,也就是說,這棵樹,我沒有經(jīng)過任何優(yōu)化的樹,預(yù)處理器會這這棵樹進(jìn)行一些預(yù)處理,比如常量放在什么地方,如果有計(jì)算的東西,把計(jì)算的結(jié)果算出來等等...
6.預(yù)處理完畢之后,此時(shí)得到一棵比較規(guī)范的樹,這棵樹就是要拿去馬上做執(zhí)行的樹,比起之前的那棵樹,這棵得到了一些優(yōu)化的解析樹
7.查詢優(yōu)化器,是MySQL里面最關(guān)鍵的東西,我們寫任何一條SQL,比如SELECT * FROM USER WHERE USERNAME = toby AND PASSWORD = 1,它會怎么去執(zhí)行?它是先執(zhí)行username = toby還是password = 1?每一條SQL的執(zhí)行順序查詢優(yōu)化器就是根據(jù)MySQL對數(shù)據(jù)統(tǒng)計(jì)表的一些信息,比如索引,比如表一共有多少數(shù)據(jù),MySQL都是有緩存起來的,在真正執(zhí)行SQL之前,他會根據(jù)自己的這些數(shù)據(jù),進(jìn)行一個(gè)綜合的判定,判斷這一次在多種執(zhí)行方式里面,到底選哪一種執(zhí)行方式,可能運(yùn)行的最快.這一步是MySQL性能中,最關(guān)鍵的核心點(diǎn),也是我們的優(yōu)化原則.我們平時(shí)所講的優(yōu)化SQL,其實(shí)說白了,就是想讓查詢優(yōu)化器,按照我們的想法,幫我們選擇最優(yōu)的執(zhí)行方案,因?yàn)槲覀儽萂ySQL更懂我們的數(shù)據(jù).MySQL看數(shù)據(jù),僅僅只是自己收集到的信息,這些信息可能是不準(zhǔn)確的,MySQL根據(jù)這些信息選了一個(gè)它自認(rèn)為最優(yōu)的方案,但是這個(gè)方案可能和我們想象的不一樣.
8.這里的查詢執(zhí)行計(jì)劃,也就是MySQL查詢中的執(zhí)行計(jì)劃,比如要先執(zhí)行username = toby還是password = 1
9.這個(gè)執(zhí)行計(jì)劃會傳給查詢執(zhí)行引擎,執(zhí)行引擎選擇存儲引擎來執(zhí)行這一份傳過來的計(jì)劃,到磁盤中的文件中去查詢,這個(gè)時(shí)候重點(diǎn)來了,影響這個(gè)查詢性能最根本的原因是什么?就是硬盤的機(jī)械運(yùn)動(dòng),也就是我們平時(shí)熟悉的IO,所以一條查詢語句是快還是慢,就是根據(jù)這個(gè)時(shí)間的IO來確定的.那怎么執(zhí)行IO又是什么來確定的?就是傳過來的這一份執(zhí)行計(jì)劃.
10.如果開了查詢緩存,則返回結(jié)果給客戶端,并且查詢緩存也放一份遂庄。
#要提高M(jìn)ySQL的更新/插入效率被济,應(yīng)首先考慮降低鎖的競爭,減少寫操作的等待時(shí)間
3.增刪改查
一涧团、INSERT語句:
基本:INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), …]
注意:
如果要插入的值列表包含所有字段并且順序一致只磷,則可以省略字段列表。
可同時(shí)插入多條數(shù)據(jù)記錄泌绣!
REPLACE 與 INSERT 完全一樣钮追,可互換。
優(yōu)化前例子:
優(yōu)化策略:
(1)當(dāng)我們需要批量插入數(shù)據(jù)的時(shí)候阿迈,這樣的語句卻會出現(xiàn)性能問題元媚。例如說,如果有需要插入100000條數(shù)據(jù)苗沧,那么就需要有100000條insert語句刊棕,每一句都需要提交到關(guān)系引擎那里去解析,優(yōu)化待逞,然后才能夠到達(dá)存儲引擎做真的插入工作甥角。上述所說的同時(shí)插入多條就是一種優(yōu)化。(經(jīng)測試识樱,大概10條同時(shí)插入是最高效的)
優(yōu)化后例子:
(2)將進(jìn)程/線程數(shù)控制在2倍于CPU數(shù)目相對合適
(3)采用順序主鍵策略(例如自增主鍵嗤无,或者修改業(yè)務(wù)邏輯,讓插入的記錄盡可能順序主鍵)
(4)考慮使用replace 語句代替insert語句怜庸。(REPLACE語句請參考下文当犯,有詳細(xì)講述)
二、DELETE語句:
DELETE FROM 表名[ 刪除條件子句](沒有條件子句割疾,則會刪除全部)
例子:
補(bǔ)充:Mysql中的truncate table和delete語句都可以刪除表里面所有數(shù)據(jù)嚎卫,但是在一些情況下有些不同!
例子:
truncate table gag;
(1)truncate table刪除速度更快宏榕,拓诸,但truncate table刪除后不記錄mysql日志胸懈,不可以恢復(fù)數(shù)據(jù)。(謹(jǐn)慎使用)
(2)如果沒有外鍵關(guān)聯(lián)恰响,innodb執(zhí)行truncate是先drop table(原始表),再創(chuàng)建一個(gè)跟原始表一樣空表,速度要遠(yuǎn)遠(yuǎn)快于delete逐條刪除行記錄趣钱。
(3)如果使用innodb_file_per_table參數(shù)烙丛,truncate table 能重新利用釋放的硬盤空間,在InnoDB Plugin中政己,truncate table為自動(dòng)回收,如果不是用InnoDB Plugin,那么需要使用optimize table來優(yōu)化表俏橘,釋放空間枢劝。
truncate table刪除表后井联,optimize table尤其重要,特別是大數(shù)據(jù)數(shù)據(jù)庫您旁,表空間可以得到釋放烙常!
(4)表有外鍵關(guān)聯(lián),truncate table刪除表數(shù)據(jù)為逐行刪除鹤盒,如果外鍵指定級聯(lián)刪除(delete cascade)蚕脏,關(guān)聯(lián)的子表也會會被刪除所有表數(shù)據(jù)。如果外鍵未指定級聯(lián)(cascde),truncate table逐行刪除數(shù)據(jù)侦锯,如果是父行關(guān)聯(lián)子表行數(shù)據(jù)驼鞭,將會報(bào)錯(cuò)。
注意:
一個(gè)大的 DELETE 或 INSERT 操作尺碰,要非常小心挣棕,因?yàn)檫@兩個(gè)操作是會鎖表的,表一鎖住亲桥,其他操作就進(jìn)不來了洛心。因此,我們要交給DBA去拆分题篷,重整數(shù)據(jù)庫策略词身,比如限制處理1000條。
另外悼凑,擴(kuò)展下刪除和索引的聯(lián)系偿枕,由于索引需要額外的維護(hù)成本;因?yàn)樗饕募菃为?dú)存在的文件,所以當(dāng)我們對數(shù)據(jù)的增加,修改,刪除,都會產(chǎn)生額外的對索引文件的操作,這些操作需要消耗額外的IO,會降低增/改/刪的執(zhí)行效率户辫。所以,在我們刪除數(shù)據(jù)庫百萬級別數(shù)據(jù)的時(shí)候嗤锉,查詢MySQL官方手冊得知?jiǎng)h除數(shù)據(jù)的速度和創(chuàng)建的索引數(shù)量是成正比的渔欢。所以我們想要?jiǎng)h除百萬數(shù)據(jù)的時(shí)候可以先刪除索引(此時(shí)大概耗時(shí)三分多鐘),然后刪除其中無用數(shù)據(jù)瘟忱,此過程需要不到兩分鐘奥额,刪除完成后重新創(chuàng)建索引(此時(shí)數(shù)據(jù)較少了)創(chuàng)建索引也非成淮保快,約十分鐘左右垫挨。與之前的直接刪除絕對是要快速很多韩肝,更別說萬一刪除中斷,一切刪除會回滾。那更是坑了九榔。
三哀峻、UPDATE語句:
UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新條件]
例子:
優(yōu)化:更新多條記錄(往后會結(jié)合MyBatics寫個(gè)實(shí)例)
更新多條記錄的多個(gè)值
(1). 盡量不要修改主鍵字段。(廢話哲泊,反正我就從沒改過..)
(2). 當(dāng)修改VARCHAR型字段時(shí)剩蟀,盡量使用相同長度內(nèi)容的值代替。
(3). 盡量最小化對于含有UPDATE觸發(fā)器的表的UPDATE操作切威。
(4). 避免UPDATE將要復(fù)制到其他數(shù)據(jù)庫的列育特。
(5). 避免UPDATE建有很多索引的列。
(6). 避免UPDATE在WHERE子句條件中的列先朦。
四缰冤、REPLACE語句:
根據(jù)應(yīng)用情況可以使用replace 語句代替insert/update語句。例如:如果一個(gè)表在一個(gè)字段上建立了唯一索引喳魏,當(dāng)向這個(gè)表中使用已經(jīng)存在的鍵值插入一條記錄锋谐,將會拋出一個(gè)主鍵沖突的錯(cuò)誤。如果我們想用新記錄的值來覆蓋原來的記錄值時(shí)截酷,就可以使用REPLACE語句涮拗。
使用REPLACE插入記錄時(shí),如果記錄不重復(fù)(或往表里插新記錄)迂苛,REPLACE功能與INSERT一樣三热,如果存在重復(fù)記錄,REPLACE就使用新記錄的值來替換原來的記錄值三幻。使用REPLACE的最大好處就是可以將DELETE和INSERT合二為一就漾,形成一個(gè)原子操作。這樣就可以不必考慮同時(shí)使用DELETE和INSERT時(shí)添加事務(wù)等復(fù)雜操作了念搬。
在使用REPLACE時(shí)抑堡,表中必須有唯一有一個(gè)PRIMARY KEY或UNIQUE索引,否則朗徊,使用一個(gè)REPLACE語句沒有意義首妖。
用法:
(1)同INSERT
含義一:與普通INSERT一樣功能
REPLACE INTO score (change_type,score,user_id) VALUES ('吃飯',10,1),('喝茶',10,1),('喝茶',10,1);
含義二:找到第一條記錄,用后面的值進(jìn)行替換
REPLACE INTO score (id,change_type,score,user_id) VALUES (1,'吃飯',10,1)
此語句的作用是向表table中插入3條記錄爷恳。如果主鍵id為1或2不存在就相當(dāng)于插入語句:
INSERT INTO score (change_type,score,user_id) VALUES (‘吃飯’,10,1),(‘喝茶’,10,1),(‘喝茶’,10,1);
如果存在相同的值則不會插入數(shù)據(jù)有缆。
(2)replace(object, search, replace),把object中出現(xiàn)search的全部替換為replace。
用法一:并不是修改數(shù)據(jù)棚壁,而只是單純做局部替換數(shù)據(jù)返還而已杯矩。
SELECT REPLACE('喝茶','茶','喝')//結(jié)果: 喝喝123
用法二:修改表數(shù)據(jù)啦,對應(yīng)下面就是袖外,根據(jù)change_type字段找到做任務(wù)的數(shù)據(jù)史隆,用bb來替換
UPDATE score SET change_type=REPLACE(change_type,'做任務(wù)','bb')1
在此,做下對比:UPDATE和REPLACE的區(qū)別:
1)UPDATE在沒有匹配記錄時(shí)什么都不做曼验,而REPLACE在有重復(fù)記錄時(shí)更新泌射,在沒有重復(fù)記錄時(shí)插入。
2)UPDATE可以選擇性地更新記錄的一部分字段蚣驼。而REPLACE在發(fā)現(xiàn)有重復(fù)記錄時(shí)就將這條記錄徹底刪除魄幕,再插入新的記錄。也就是說颖杏,將所有的字段都更新了纯陨。
其實(shí)REPLACE更像INSERT與DELETE的結(jié)合。
單表查詢優(yōu)化:
(0)可以先使用EXPLAIN關(guān)鍵字可以讓你知道MySQL是如何處理你的SQL語句的留储。這可以幫我們分析是查詢語句或是表結(jié)構(gòu)的性能瓶頸翼抠。
(1)寫sql要明確需要的字段,要多少就寫多少字段获讳,而不是濫用 select *
(2)可以用使用連接(JOIN)來代替子查詢
(3)使用分頁語句:limit start , count 或者條件 where子句時(shí)阴颖,有什么可限制的條件盡量加上,查一條就limit一條丐膝。做到不濫用量愧。比如說我之前做過的的p2p項(xiàng)目,只是需要知道有沒有一個(gè)滿標(biāo)的借款,這樣的話就可以用上 limit 1帅矗,這樣mysql在找到一條數(shù)據(jù)后就停止搜索偎肃,而不是全文搜索完再停止。
(4)開啟查詢緩存:
大多數(shù)的MySQL服務(wù)器都開啟了查詢緩存浑此。這是提高查詢有效的方法之一累颂。當(dāng)有很多相同的查詢被執(zhí)行了多次的時(shí)候,這些查詢結(jié)果會被放到一個(gè)緩存中凛俱,這樣紊馏,后續(xù)的相同的查詢就不用操作表而直接訪問緩存結(jié)果了。
查詢緩存工作流程:
A):服務(wù)器接收SQL蒲犬,以SQL+DB+Query_cache_query_flags作為hash查找鍵朱监;
B):找到了相關(guān)的結(jié)果集就將其返回給客戶端;
C):如果沒有找到緩存則執(zhí)行權(quán)限驗(yàn)證暖哨、SQL解析赌朋、SQL優(yōu)化等一些列的操作凰狞;
D):執(zhí)行完SQL之后篇裁,將結(jié)果集保存到緩存
當(dāng)然沛慢,并不是每種情況都適合使用緩存,衡量打開緩存是否對系統(tǒng)有性能提升是一個(gè)整體的概念达布。那怎么判斷要不要開啟緩存呢团甲,如下:
1)通過緩存命中率判斷, 緩存命中率 = 緩存命中次數(shù) (Qcache_hits) / 查詢次數(shù) (Com_select)、
2)通過緩存寫入率, 寫入率 = 緩存寫入次數(shù) (Qcache_inserts) / 查詢次數(shù) (Qcache_inserts)
3)通過 命中-寫入率 判斷, 比率 = 命中次數(shù) (Qcache_hits) / 寫入次數(shù) (Qcache_inserts), 高性能MySQL中稱之為比較能反映性能提升的指數(shù),一般來說達(dá)到3:1則算是查詢緩存有效,而最好能夠達(dá)到10:1
相關(guān)參數(shù)及命令:
與緩存相關(guān)的主要參數(shù)如下表所示黍聂√煽啵可以使用命令SHOW VARIABLES LIKE '%query_cache%'查看
緩存數(shù)據(jù)失效時(shí)機(jī)
在表的結(jié)構(gòu)或數(shù)據(jù)發(fā)生改變時(shí),查詢緩存中的數(shù)據(jù)不再有效产还。有這些INSERT匹厘、UPDATE、 DELETE脐区、TRUNCATE愈诚、ALTER TABLE、DROP TABLE或DROP DATABASE會導(dǎo)致緩存數(shù)據(jù)失效牛隅。所以查詢緩存適合有大量相同查詢的應(yīng)用炕柔,不適合有大量數(shù)據(jù)更新的應(yīng)用。
可以使用下面三個(gè)SQL來清理查詢緩存:
1媒佣、FLUSH QUERY CACHE; // 清理查詢緩存內(nèi)存碎片匕累。
2、RESET QUERY CACHE; // 從查詢緩存中移出所有查詢默伍。
3欢嘿、FLUSH TABLES; //關(guān)閉所有打開的表,同時(shí)該操作將會清空查詢緩存中的內(nèi)容也糊。
InnoDB與查詢緩存:
Innodb會對每個(gè)表設(shè)置一個(gè)事務(wù)計(jì)數(shù)器,里面存儲當(dāng)前最大的事務(wù)ID.當(dāng)一個(gè)事務(wù)提交時(shí),InnoDB會使用MVCC中系統(tǒng)事務(wù)ID最大的事務(wù)ID跟新當(dāng)前表的計(jì)數(shù)器.
只有比這個(gè)最大ID大的事務(wù)能使用查詢緩存,其他比這個(gè)ID小的事務(wù)則不能使用查詢緩存.
另外,在InnoDB中,所有有加鎖操作的事務(wù)都不使用任何查詢緩存
(MVCC (Multiversion Concurrency Control)炼蹦,即多版本并發(fā)控制技術(shù),它使得大部分支持行鎖的事務(wù)引擎,不再單純的使用行鎖來進(jìn)行數(shù)據(jù)庫的并發(fā)控制显设,取而代之的是把數(shù)據(jù)庫的行鎖與行的多個(gè)版本結(jié)合起來框弛,只需要很小的開銷,就可以實(shí)現(xiàn)非鎖定讀,從而大大提高數(shù)據(jù)庫系統(tǒng)的并發(fā)性能)
多表查詢連接的選擇:
相信這內(nèi)連接捕捂,左連接什么的大家都比較熟悉了瑟枫,當(dāng)然還有左外連接什么的,基本用不上我就不貼出來了指攒。這圖只是讓大家回憶一下慷妙,各種連接查詢。 然后要告訴大家的是允悦,需要根據(jù)查詢的情況膝擂,想好使用哪種連接方式效率更高。
二、MySQL的JOIN實(shí)現(xiàn)原理
在MySQL 中架馋,只有一種Join 算法狞山,就是大名鼎鼎的Nested Loop Join,他沒有其他很多數(shù)據(jù)庫所提供的Hash Join叉寂,也沒有Sort Merge Join萍启。顧名思義,Nested Loop Join 實(shí)際上就是通過驅(qū)動(dòng)表的結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù)屏鳍,然后一條一條的通過該結(jié)果集中的數(shù)據(jù)作為過濾條件到下一個(gè)表中查詢數(shù)據(jù)勘纯,然后合并結(jié)果。如果還有第三個(gè)參與Join钓瞭,則再通過前兩個(gè)表的Join 結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù)驳遵,再一次通過循環(huán)查詢條件到第三個(gè)表中查詢數(shù)據(jù),如此往復(fù)山涡。 ——摘自《MySQL 性能調(diào)優(yōu)與架構(gòu)設(shè)計(jì)》
三堤结、補(bǔ)充:mysql對sql語句的容錯(cuò)問題
即在sql語句不完全符合書寫建議的情況,mysql會允許這種情況佳鳖,盡可能解釋它:
1)一般cross join后面加上where條件霍殴,但是用cross join+on也是被解釋為cross join+where;
2)一般內(nèi)連接都需要加上on限定條件系吩,如上面場景一来庭;如果不加會被解釋為交叉連接;
3)如果連接表格使用的是逗號穿挨,會被解釋為交叉連接月弛;
超大型數(shù)據(jù)盡可能盡力不要寫子查詢,使用連接(JOIN)去替換它:
當(dāng)然科盛,關(guān)于這句話帽衙,也不一定就全是這樣。
1)因?yàn)樵诖笮偷臄?shù)據(jù)處理中贞绵,子查詢是非常常見的厉萝,特別是在查詢出來的數(shù)據(jù)需要進(jìn)一步處理的情況,無論是可讀性還是效率上榨崩,這時(shí)候的子查都是更優(yōu)谴垫。
2)然而在一些特定的場景,可以直接從數(shù)據(jù)庫讀取就可以的母蛛,比如一個(gè)表(A表 a翩剪,b,c字段彩郊,需要內(nèi)部數(shù)據(jù)交集)join自己的效率必然比放一個(gè)子查在where中快得多前弯。
使用聯(lián)合(UNION)來代替手動(dòng)創(chuàng)建的臨時(shí)表
UNION是會把結(jié)果排序的r阶骸!恕出!
union查詢:它可以把需要使用臨時(shí)表的兩條或更多的select查詢合并的一個(gè)查詢中(即把兩次或多次查詢結(jié)果合并起來询枚。)。在客戶端的查詢會話結(jié)束的時(shí)候剃根,臨時(shí)表會被自動(dòng)刪除哩盲,從而保證數(shù)據(jù)庫整齊前方、高效狈醉。使用union來創(chuàng)建查詢的時(shí)候,我們只需要用UNION作為關(guān)鍵字把多個(gè)select語句連接起來就可以了惠险,要注意的是所有select語句中的字段數(shù)目要想同苗傅。
要求:兩次查詢的列數(shù)必須一致(列的類型可以不一樣,但推薦查詢的每一列班巩,相對應(yīng)的類型要一樣)
可以來自多張表的數(shù)據(jù):多次sql語句取出的列名可以不一致渣慕,此時(shí)以第一個(gè)sql語句的列名為準(zhǔn)。
如果不同的語句中取出的行抱慌,有完全相同(這里表示的是每個(gè)列的值都相同)逊桦,那么union會將相同的行合并,最終只保留一行抑进。也可以這樣理解强经,union會去掉重復(fù)的行。
如果不想去掉重復(fù)的行寺渗,可以使用union all匿情。
如果子句中有order by,limit,需用括號()包起來信殊。推薦放到所有子句之后炬称,即對最終合并的結(jié)果來排序或篩選。
注意:
1涡拘、UNION 結(jié)果集中的列名總是等于第一個(gè) SELECT 語句中的列名
2玲躯、UNION 內(nèi)部的 SELECT 語句必須擁有相同數(shù)量的列。列也必須擁有相似的數(shù)據(jù)類型鳄乏。同時(shí)跷车,每條 SELECT 語句中的列的順序必須相同
UNION ALL的作用和語法:
默認(rèn)地,UNION 操作符選取不同的值汞窗。如果允許重復(fù)的值姓赤,請使用 UNION ALL。當(dāng) ALL 隨 UNION 一起使用時(shí)(即 UNION ALL)仲吏,不消除重復(fù)行不铆。
總結(jié)
(1)對于要求全面的結(jié)果時(shí)蝌焚,我們需要使用連接操作(LEFT JOIN / RIGHT JOIN / FULL JOIN);
(2)應(yīng)盡量避免在 where 子句中對字段進(jìn)行 null 值判斷誓斥,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描只洒,如:
備注、描述劳坑、評論之類的可以設(shè)置為 NULL毕谴,其他最好不要使用NULL。
不要以為 NULL 不需要空間距芬,比如:char(100) 型涝开,在字段建立時(shí),空間就固定了框仔, 不管是否插入值(NULL也包含在內(nèi))舀武,都是占用 100個(gè)字符的空間的,如果是varchar這樣的變長字段离斩, null 不占用空間银舱。
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒有null值跛梗,然后這樣查詢:
select id from t where num = 0
(3)in 和 not in 也要慎用寻馏,否則會導(dǎo)致全表掃描,如:
對于連續(xù)的數(shù)值核偿,能用 between 就不要用 in 了:
很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:
(4)盡量使用數(shù)字型字段诚欠,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型,這會降低查詢和連接的性能宪祥,并會增加存儲開銷聂薪。這是因?yàn)橐嬖谔幚聿樵兒瓦B 接時(shí)會逐個(gè)比較字符串中每一個(gè)字符,而對于數(shù)字型而言只需要比較一次就夠了蝗羊。
(5)盡量使用表變量來代替臨時(shí)表藏澳。如果表變量包含大量數(shù)據(jù),請注意索引非常有限(只有主鍵索引)耀找。
(6)不要以為使用MySQL的一些連接操作對查詢有多么大的改善翔悠,其實(shí)核心是索引