選取書中特別有代表性的點來講:
一:Mysql邏輯架構(gòu)
mysql的架構(gòu)解析:
當(dāng)一個sql請求從客戶端請求過來语御,先經(jīng)過連接池,連接池如果有空閑的線程,則可以直接用,如果沒有就新創(chuàng)建一個建立連接卢肃,如果是查詢類的sql,會先檢查是否命中緩存才顿,有緩存則直接返回緩存結(jié)果給客戶端莫湘,如果沒有命中緩存,則經(jīng)過解析器解析sql語法郑气,會解析出關(guān)鍵字和非關(guān)鍵字幅垮,解析sql是否合法,不合法會直接報錯終止線程竣贪,合法的話會進(jìn)入優(yōu)化器军洼,優(yōu)化器會為sql生成最優(yōu)的執(zhí)行計劃巩螃,例如選擇最合適的索引演怎,生成執(zhí)行計劃后調(diào)用存儲引擎的API,讓存儲引擎開始工作避乏,即到文件系統(tǒng)下進(jìn)行數(shù)據(jù)的讀取和寫入爷耀,并最終把結(jié)果返回給客戶端,如果是查詢類sql還會把結(jié)果緩存下來拍皮。
二:事務(wù)
事務(wù)的ACID特性
原子性(atomicity)歹叮,事務(wù)要么全部提交跑杭,要么全部回滾
一致性(consistency),數(shù)據(jù)庫總是從一個一致性的狀態(tài)轉(zhuǎn)換到另外一個一致性的狀態(tài)
隔離性(isolation)咆耿,通常一個事務(wù)所做的修改在最終提交以前德谅,對其他事務(wù)是不可見的(也有例外,隔離性最低等級未提交讀對其他事務(wù)是可見的)
持久性(durability)萨螺,一旦事務(wù)提交窄做,則其所做的修改就會永久保存到數(shù)據(jù)庫中。
注:實際應(yīng)用中慰技,要實現(xiàn)ACID全部特性非常難椭盏,一個兼容ACID的數(shù)據(jù)庫系統(tǒng),需要做很多復(fù)雜但可能用戶并沒有覺察到的工作吻商,才能確保ACID的實現(xiàn)掏颊。平時根據(jù)你自己業(yè)務(wù)是否需要事務(wù),來選擇合適的存儲引擎艾帐。innodb支持事務(wù)乌叶,myisam不支持事務(wù),但大部分場景都是用innodb的柒爸,mysql5.5以后的版本都默認(rèn)innodb引擎
隔離級別
ACID特性中的隔離性分四個等級枉昏,由低到高(級別越高,安全性越高揍鸟,級別越低兄裂,并發(fā)能力越好,性能開銷低):
READ UNCOMMITTED(未提交讀)
將事務(wù)設(shè)置為未提交讀等級
事務(wù)A
事務(wù)B
結(jié)論:事務(wù)B更新了一條記錄阳藻,但是沒有提交晰奖,此時事務(wù)A可以查詢出未提交記錄,造成臟讀現(xiàn)象腥泥。未提交讀是最低的隔離級別匾南,很少應(yīng)用到
READ COMMITTED(提交讀)
將事務(wù)設(shè)置為提交讀等級
事務(wù)A
事務(wù)B
結(jié)論:已提交讀隔離級別解決了臟讀的問題,但是出現(xiàn)了不可重復(fù)讀的問題蛔外,即事務(wù)B更新了數(shù)據(jù)前后蛆楞,事務(wù)A在兩次查詢的數(shù)據(jù)不一致
REPEATABLE READ(可重復(fù)讀)
實驗略〖醒幔可重復(fù)讀隔離級別解決了臟讀和不可重復(fù)讀問題豹爹,它只允許讀取已提交記錄,而且在一個事務(wù)兩次讀取一個記錄期間矛纹,其他事務(wù)部的更新該記錄臂聋。但該事務(wù)不要求與其他事務(wù)可串行化。例如,當(dāng)一個事務(wù)可以找到由一個已提交事務(wù)更新的記錄孩等,但是可能產(chǎn)生幻讀問題艾君。幻讀就是事務(wù)A提交事務(wù)后再次查詢肄方,如果其他事務(wù)插入新行冰垄,那么會出現(xiàn)新行產(chǎn)生幻讀問題。(注意是可能权她,因為數(shù)據(jù)庫對隔離級別的實現(xiàn)有所差別)播演。mysql是默認(rèn)這種隔離級別。
SERIALIZABLE(可串行化)
實驗略伴奥。它通過強(qiáng)制事務(wù)串行執(zhí)行写烤,比如在事務(wù)A執(zhí)行過程中會禁止其他事務(wù)插入數(shù)據(jù),避免了前面說的幻讀的問題拾徙。SERIALIZABLE會在讀取的每一行數(shù)據(jù)上都加鎖洲炊,所以可能導(dǎo)致大量的超時和鎖爭用的問題。實際應(yīng)用中也很少用到這個隔離級別尼啡,只有在非常需要確保數(shù)據(jù)的一致性而且可以接受沒有并發(fā)的情況下暂衡,才考慮采用該級別。
事務(wù)死鎖
死鎖是指兩個或者多個事務(wù)在同一資源上相互占用崖瞭,并請求鎖定對方占用的資源狂巢,從而導(dǎo)致惡性循環(huán)的現(xiàn)象。當(dāng)多個事務(wù)試圖以不同的順序鎖定資源時书聚,就可能會產(chǎn)生死鎖唧领。多個事務(wù)同時鎖定同一個資源時,也會產(chǎn)生死鎖雌续。舉例:事務(wù)A先更新id=1再更新id=2,事務(wù)B同時先更新id=2再更新id=1斩个,兩個事務(wù)互相占有對方資源,然后請求對方資源驯杜,產(chǎn)生死鎖受啥。
三、數(shù)據(jù)類型
數(shù)據(jù)類型選擇
更小的通常更好鸽心。
應(yīng)該盡量使用可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型滚局。例如能用smallint盡量不用int,因為更小的數(shù)據(jù)類型通常更快顽频,它們占用更少的磁盤藤肢、內(nèi)存和CPU緩存,并且處理時需要的CPU周期也更少冲九。
簡單就好
簡單數(shù)據(jù)類型的操作通常需要更少的CPU周期谤草,例如不用字符串,而是用更簡單的整型存儲IP地址
盡量避免NULL
當(dāng)可為NULL的列被索引時莺奸,每個索引記錄需要一個額外的字節(jié)丑孩,因此可為NULL的列會使用更多的存儲空間。
幾種重要的數(shù)據(jù)類型
整型
整型取值范圍
MySQL可以為整數(shù)類型指定寬度灭贷,例如INT(11)温学,對于存儲和計算來說,INT(1)和INT(5)是相同的甚疟,區(qū)別在于字段類型加入 zerofill 參數(shù)后仗岖,值1234在INT(1)顯示為1234,在INT(5)顯示為01234览妖,即不夠?qū)挾仍谇懊嫜a(bǔ)0
實數(shù)
FLOAT和DOUBLE類型支持使用標(biāo)準(zhǔn)的浮點運(yùn)算進(jìn)行近似計算轧拄。
DECIMAL類型用于存儲精確的小數(shù)。
浮點類型由于取值范圍的影響讽膏,會導(dǎo)致實際保存與我們期望的不符合檩电,F(xiàn)LOAT類型整數(shù)超過6位就會有誤差,所以金錢相關(guān)的盡量用DECIMAL類型
DECIMAL因為需要額外的空間和計算開銷府树,所以應(yīng)該盡量只在對小數(shù)進(jìn)行精確計算時才使用DECIMAL俐末。但在數(shù)據(jù)量比較大的時候,可以考慮使用BIGINT代替DECIMAL奄侠,將需要存儲的貨幣單位根據(jù)小數(shù)的位數(shù)乘以相應(yīng)的倍數(shù)即可
字符串類型
VARCHAR類型
優(yōu)點:用于存儲可變長字符串卓箫,越短的字符串使用越少的空間,VARCHAR節(jié)省了存儲空間垄潮,所以對性能也有幫助烹卒。
缺點:VARCHAR需要使用1或2個額外字節(jié)記錄字符串的長度,由于行是變長的弯洗,在UPDATE時可能使行變得比原來更長甫题,這就導(dǎo)致需要做額外的工作,會產(chǎn)生碎片
使用場景:字符串列的最大長度比平均長度大很多涂召;列的更新很少坠非,所以碎片不是問題;使用了像UTF-8這樣復(fù)雜的字符集果正,每個字符都使用不同的字節(jié)數(shù)進(jìn)行存儲炎码。
CHAR類型
使用場景:CHAR非常適合存儲密碼的MD5值,因為這是一個定長的值秋泳。對于經(jīng)常變更的數(shù)據(jù)潦闲,CHAR也比VARCHAR更好,因為定長的CHAR類型不容易產(chǎn)生碎片迫皱。對于非常短的列歉闰,CHAR比VARCHAR在存儲空間上也更有效率辖众。例如用CHAR(1)來存儲只有Y和N的值,如果采用單字節(jié)字符集(5)只需要一個字節(jié)和敬,但是VARCHAR(1)卻需要兩個字節(jié)凹炸,因為還有一個記錄長度的額外字節(jié)。
日期和時間類型
DATETIME和TIMESTAMP的比較
TIMESTAMP比DATETIME占空間小昼弟。DATETIME是使用8個字節(jié)的存儲空間啤它,TIMESTAMP是使用4個字節(jié)的存儲空間。
TIMESTAMP的范圍比DATETIME小得多舱痘。DATETIME能保存大范圍的值变骡,從1001年到9999年,精度為秒芭逝。TIMESTAMP只能表示從1970年到2038年塌碌,但這種范圍已經(jīng)可以滿足大部分日常使用。
TIMESTAMP顯示方式比DATETIME更靈活旬盯。DATETIME存什么顯示什么誊爹,TIMESTAMP存儲的是時間戳,顯示mysql所在時區(qū)的時間瓢捉,如果儲存時的時區(qū)和檢索時的時區(qū)不一樣频丘,那么拿出來的數(shù)據(jù)也不一樣。
范式反范式的優(yōu)點和缺點
范式的優(yōu)點
范式化的更新操作通常比反范式化要快泡态。
當(dāng)數(shù)據(jù)較好地范式化時搂漠,就只有很少或者沒有重復(fù)數(shù)據(jù),所以只需要修改更少的數(shù)據(jù)某弦。
范式化的表通常更小桐汤,可以更好地放在內(nèi)存里,所以執(zhí)行操作會更快靶壮。
很少有多余的數(shù)據(jù)意味著檢索列表數(shù)據(jù)時更少需要DISTINCT或者GROUP BY語句怔毛。
范式的缺點
通常需要關(guān)聯(lián)。稍微復(fù)雜一些的查詢語句在符合范式的schema上都可能需要至少一次關(guān)聯(lián)腾降,也許更多拣度。這不但代價昂貴,也可能使一些索引策略無效
反范式的優(yōu)點
反范式化的schema因為所有數(shù)據(jù)都在一張表中螃壤,可以很好地避免關(guān)聯(lián)抗果。
如果不需要關(guān)聯(lián)表,則對大部分查詢最差的情況——即使表沒有使用索引——是全表掃描奸晴。當(dāng)數(shù)據(jù)比內(nèi)存大時這可能比關(guān)聯(lián)要快得多冤馏,因為這樣避免了隨機(jī)I/O(14)。
單獨(dú)的表也能使用更有效的索引策略寄啼。
反范式的缺點
當(dāng)MySQL需要掃描表字段的索引逮光,對于每一行找到的數(shù)據(jù)代箭,將需要到表里檢查數(shù)據(jù)是不是符合條件。如果只有一小部分符合條件是效率低下
通過是范式化和反范式化兩者混用
四涕刚、索引
索引大大減少了服務(wù)器需要掃描的數(shù)據(jù)量嗡综。
索引可以幫助服務(wù)器避免排序和臨時表。
索引可以將隨機(jī)I/O變?yōu)轫樞騃/O副女。
B+tree索引
B-tree是從最簡單的二叉樹進(jìn)化到平衡二叉樹蛤高,再進(jìn)化到多路平衡查找樹蚣旱,即B-tree碑幅,最后進(jìn)化到B-tree改進(jìn)版B+tree,innodb采用的就是B+tree
B-tree的非葉子節(jié)點只存儲鍵值信息塞绿,這樣節(jié)省了磁盤塊的空間沟涨,可以實現(xiàn)更多路,使樹的高度更小异吻,加快查找速度
所有葉子節(jié)點之間都有一個鏈指針裹赴。
數(shù)據(jù)記錄都存放在葉子節(jié)點中
索引命中情況
全值匹配
全值匹配指的是和索引中的所有列進(jìn)行匹配
匹配最左前綴
只使用索引的第一列
匹配列前綴
只匹配索引列的值的開頭部分
匹配范圍值
只使用了索引的第一列進(jìn)行范圍查找
精確匹配某一列并范圍匹配另外一列
索引命中限制
如果不是按照索引的最左列開始查找,則無法使用索引
不能跳過索引中的列
如果查詢中有某個列的范圍查詢诀浪,則其右邊所有列都無法使用索引優(yōu)化查找
高性能的索引策略
獨(dú)立的列棋返,索引列不能是表達(dá)式的一部分,也不能是函數(shù)的參數(shù)雷猪。WHERE actor_id + 1 = 5;是一個表達(dá)式
選擇合適的索引列順序
以下面的查詢?yōu)槔?/p>
是應(yīng)該創(chuàng)建一個(staff_id睛竣,customer_id)索引還是應(yīng)該顛倒一下順序?如下所示,
根據(jù)經(jīng)驗法則求摇,應(yīng)該將索引列customer_id放到前面射沟,因為對應(yīng)條件值的customer_id數(shù)量更小。
聚簇索引
下圖展示了聚簇索引中的記錄是如何存放的与境。注意到验夯,葉子頁包含了行的全部數(shù)據(jù),但是節(jié)點頁只包含了索引列摔刁。
如果沒有定義主鍵挥转,InnoDB會選擇一個唯一的非空索引代替。如果沒有這樣的索引共屈,InnoDB會隱式定義一個主鍵來作為聚簇索引扁位。InnoDB只聚集在同一個頁面中的記錄。包含相鄰鍵值的頁面可能會相距甚遠(yuǎn)趁俊。