高性能MYSQL讀書筆記

1.鎖有兩種類型:讀鎖和寫鎖吧秕。讀鎖是共享的,或者說是相互不阻塞的庵芭,多個客戶在同一時刻可以同時讀取同一資源德迹,而互不干擾;寫鎖則是排他的,也就是說一個寫鎖會阻塞其他的寫鎖和讀鎖抑淫。另外绷落,寫鎖比讀鎖有更高的優(yōu)先級,也即在同時有讀鎖和寫鎖的情況寫始苇,寫鎖可能會插入到隊列前面執(zhí)行砌烁。

2.事務的特性:原子性、一致性催式、隔離性函喉、持久性。

原子性:一個事務必須被視為一個不可分割的最小工作單元荣月,整個事務中的所有操作要么全部提交成功管呵,要么全部失敗回滾,對于一個事務來說哺窄,不可能只執(zhí)行其中一部分操作捐下,這就是事務的原子性;
一致性:數(shù)據(jù)庫總是從一個一致性的狀態(tài)轉(zhuǎn)換到另外一個一致性的狀態(tài)萌业。
隔離性:通常來說坷襟,一個事務所做的修改在最終提交之前,對其他事務是不可見的生年。
持久性:一旦事務被提交婴程,則其所做的修改會永久保存到數(shù)據(jù)庫中。此時即使系統(tǒng)崩潰晶框,修改的數(shù)據(jù)也不會丟失排抬。
3.對于一些不需要事務的查詢類應用,選擇一個非事務型的存儲引擎授段,可以獲得更高的性能蹲蒲。

4.事務的隔離級別:READ_UNCOMMITTED、READ_COMMITTED侵贵、REPEATABLE_READ届搁、SERIALIZABLE。

READ_UNCOMMITTED:在此級別就算沒提交窍育,事務中的修改對其他事務也是可見的卡睦;
READ_COMMITTED:此級別滿足了前面事務的簡單定義,即一個事務開始時漱抓,其所做的修改只對當前事務可見表锻,但是其未解決重復讀的問題,即當前事務在重復讀取某條數(shù)據(jù)期間乞娄,如果另一事務對該數(shù)據(jù)進行了修改瞬逊,那么當前事務就會讀取到不一樣的數(shù)據(jù)显歧;
REPEATABLE_READ:此級別解決了事務重復讀的問題,但是卻沒有解決幻讀的問題确镊,即如果當前事務讀取的是一定范圍內(nèi)的數(shù)據(jù)士骤,而領一事務此時插入了一條數(shù)據(jù),那么當前事務兩次讀取的數(shù)據(jù)還是不一致蕾域;
SERIALIZABLE:可串行化是事務讀取的最高級別拷肌,其強制要求事務在讀取的時候串行化的執(zhí)行,其安全性最高旨巷,但卻產(chǎn)生了鎖的競爭等一系列問題巨缘。
5.死鎖是指兩個或多個事務在同一資源上相互占用,并且相互請求對方所占用的資源契沫,從而導致惡性循環(huán)的現(xiàn)象带猴。

6.為了解決死鎖的問題,數(shù)據(jù)庫一般實現(xiàn)了各種死鎖檢測和死鎖超時的機制懈万,越是復雜的數(shù)據(jù)庫系統(tǒng)越能檢測到死鎖的循環(huán)依賴拴清,并且返回一個錯誤。另外一種處理方式是会通,當獲取鎖超時時就放棄獲取該鎖口予。這里InnoDB實現(xiàn)的方式是當檢測到獲取鎖超時時,其會檢測鎖定行數(shù)最少的事務涕侈,并對其進行回滾沪停。

7.死鎖產(chǎn)生的原因一般有兩種:一種是由于事務獲取的數(shù)據(jù)之間有沖突,這種情況很難避免裳涛;另一種是由于數(shù)據(jù)庫的實現(xiàn)方式產(chǎn)生的木张。

8.對磁盤中數(shù)據(jù)的修改操作每次都要寫兩次磁盤,如果對于每次修改操作都持久化到磁盤端三,那么就需要在多個地方隨機移動磁頭舷礼,而事務日志是指存儲引擎在修改表數(shù)據(jù)時只需要修改其內(nèi)存拷貝,再把修改行為持久化到硬盤上的事務日志中郊闯,而不用每次都將修改的數(shù)據(jù)本身持久到磁盤妻献。并且事務日志采用的是追加的方式,因此寫日志的操作是磁盤上一小塊區(qū)域內(nèi)的順序I/O团赁,而不像隨機I/O需要在磁盤的多個地方移動磁頭育拨。

9.MySQL默認采用自動提交的模式,也就是說如果不是顯示的提交一個事務欢摄,那么每一個查詢都將當做一個事務執(zhí)行熬丧。在當前鏈接中可以通過設置AUTOCOMMIT變量設置是否采用自動提交,設置方式為SET AUTOCOMMIT=1怀挠,設置了之后所有的查詢都將當做一個事務執(zhí)行锹引,直到執(zhí)行COMMIT提交或者ROLLBACK回滾矗钟,此時該事務結束唆香,開始執(zhí)行下一個事務嫌变。另外需要注意的是,對于一些非事務的表躬它,如MyISAM或內(nèi)存表腾啥,其是非事務類型的表,也就是說對于這類表沒有COMMIT和ROLLBACK的概念冯吓,所有的查詢都處于AUTOCOMMIT的模式倘待。

10.MySQL也支持LOCK TABLES和UNLOCK TABLES語句,這是在服務器實現(xiàn)的组贺,和存儲引擎無關凸舵。

11.LOCK TABLES和事務之間相互影響的話,情況會變得非常復雜失尖,在某些MySQL版本中甚至產(chǎn)生無法預料的結果啊奄。因此,這里建議掀潮,除了事務中禁用了AUTOCOMMIT菇夸,可以使用LOCK TABLES之外,其他任何時候都不要顯示地執(zhí)行LOCK TABLES仪吧,不管使用的是什么存儲引擎庄新。

12.MySQL和其他多種類型數(shù)據(jù)庫基于并發(fā)考慮,一般都會同時實現(xiàn)多版本并發(fā)控制(MVCC)薯鼠。MVCC是行集鎖的一個變種择诈,其在很多情況下避免了加鎖操作,因而開銷更低出皇,并且在大多數(shù)情況下實現(xiàn)了非阻塞的讀操作羞芍,寫操作也只鎖定必要的行。MVCC的實現(xiàn)是通過保存數(shù)據(jù)在某個時間節(jié)點的快照來實現(xiàn)的恶迈。也就是說涩金,不管需要多長時間,每個事務看到的數(shù)據(jù)都是一致的暇仲。而根據(jù)事務開始時間的不同步做,每個事務對同一張表,同一時刻看到的數(shù)據(jù)可能是不一樣的奈附。

13.InnoDB的MVCC全度,是通過在每行記錄后面保存兩隱藏的列來實現(xiàn)的。這兩個列斥滤,一個保存了行的創(chuàng)建時間将鸵,一個保存了行的過期時間(刪除時間)勉盅。當然,存儲的并不是實際的時間值顶掉,而是系統(tǒng)版本號草娜。每開始一個新的事務,系統(tǒng)版本號都會自動遞增痒筒。事務開始時刻的系統(tǒng)版本號會作為事務版本號宰闰,用來和查詢到的每行記錄的版本號進行比較,以下是REPEATABLE_READ隔離級別下簿透,MVCC是如何操作的:

SELECT:

InnoDB會根據(jù)以下兩個條件檢查每行記錄:

 a.InnoDB只查找版本早于當前事務版本的數(shù)據(jù)行(也就是移袍,行的系統(tǒng)版本號小于或等于當前事務的系統(tǒng)      版本號),這樣可以確保事務讀取的行老充,要么是在事務開始前已經(jīng)存在的葡盗,要么是事務自身插入或修改        過的。

 b.行的刪除版本要么未定義啡浊,要么大于當前事務版本號觅够。這可以確保,事務讀取到的行虫啥,在事務開始之        前未被刪除蔚约。

INSERT:

InnoDB為新插入的每一行保存當前系統(tǒng)版本號作為行版本號。

DELETE:

InnoDB為刪除的每一行保存當前系統(tǒng)版本號作為行刪除標識涂籽。

UPDATE:

InnoDB為插入一行新記錄苹祟,保存當前系統(tǒng)版本號作為當前行版本號,同時保存當前系統(tǒng)版本號到原來的       行作為刪除標識评雌。

保存這兩個額外的系統(tǒng)版本號树枫,使大多數(shù)讀操作都可以不用加鎖。這樣設計使得讀數(shù)據(jù)操作很簡單景东,性能很好砂轻,并且能保證讀取到符合標準的行。不足之處是每行記錄都需要額外的存儲空間斤吐,需要做更多的檢查工作以及額外的維護工作搔涝。

14.InnoDB采用MVCC來支持高并發(fā),并且實現(xiàn)了四個標準的隔離級別和措。其默認級別是REPEATABLE_READ庄呈,并且通過間隙鎖(next-key locking)策略防止幻讀的出現(xiàn)。

15.InnoDB內(nèi)部做了很多優(yōu)化派阱,包括從磁盤讀取數(shù)據(jù)時采用的可預測性預讀诬留,能夠自動在內(nèi)存中創(chuàng)建hash索引以加速讀操作的自適應哈希索引,以及能夠加速插入操作的插入緩沖區(qū)等。

16.基準測試的作用:

①驗證基于系統(tǒng)的一些假設文兑,確認這些假設是否符合實際情況盒刚;

②重現(xiàn)系統(tǒng)中的某些異常行為,以解決這些異常绿贞;

③測試系統(tǒng)當前的運行情況因块。如果不清楚系統(tǒng)當前的性能,就無法確認某些優(yōu)化的效果如何樟蠕。也可以利用歷史的基準測試結果來分析診斷一些無法預測的問題贮聂;

④模擬比當前系統(tǒng)更高的負載,以找出系統(tǒng)隨著壓力增加而可能遇到的擴展瓶頸寨辩;

⑤規(guī)劃未來的業(yè)務增長〖弑基準測試可以評估在項目未來的負載下靡狞,需要什么樣的硬件,需要多大容量的網(wǎng)絡隔嫡,以及其他的相關資源甸怕;

⑥測試應用適應可變環(huán)境的能力。例如腮恩,通過基準測試梢杭,可以發(fā)現(xiàn)系統(tǒng)在隨機的并發(fā)峰值下的性能表現(xiàn),或者是不同配置的服務器之間的性能表現(xiàn)秸滴∥淦酰基準測試也可以測試系統(tǒng)對不同數(shù)據(jù)分布的處理能力。

17.針對整個系統(tǒng)做集成測試而不是單組價測試的原因:

①測試整個應用系統(tǒng)荡含,包括web服務器咒唆、應用代碼、網(wǎng)絡和數(shù)據(jù)庫是非常有用的释液,因為用戶關注的并不僅僅是MySql本身的性能全释,而是應用整體的性能;

②MySql并非總是應用的瓶頸误债,通過整體的測試可以揭示這一點浸船;

③只有對應用做整體測試,才能發(fā)現(xiàn)各部分之間的緩存帶來的影響寝蹈;

④整體應用的集成式測試更能揭示應用的整體表現(xiàn)李命,而單組件的測試很難做到這一點。

18.基于如下情況躺盛,可以只測試MySql:

①需要比較不同的schema或查詢的性能项戴;

②針對應用中某個具體問題的測試;

③為了避免漫長的基準測試槽惫,可以通過一個短期的基準測試周叮,做快速的“周期循環(huán)”辩撑,來檢測出某些調(diào)整后的結果。

19.Thread.isAlive()方法只有在當前線程在運行的時候才會返回true(也即調(diào)用start()方法運行之后仿耽,new了一個Thread當前線程是不會處于活躍狀態(tài)的)合冀。

20.優(yōu)化一個任務有兩個方向:執(zhí)行時間和等待時間。如果是優(yōu)化任務的執(zhí)行時間项贺,則應該定位不同的子任務花費的時間君躺,然后優(yōu)化去掉一些子任務,降低一些子任務的執(zhí)行頻率或者提升一些子任務的執(zhí)行效率开缎;而優(yōu)化任務的等待時間則要復雜一些棕叫,因為等待有可能是其他系統(tǒng)間接影響導致,也可能是爭用磁盤或CPU資源導致奕删。

21.整數(shù)數(shù)據(jù)類型:TINYINT俺泣,SMALLINT,MEDIUMINT完残,INT伏钠,BIGINT。這幾種類型分別使用8谨设,16熟掂,24,32扎拣,64位存儲空間赴肚,并且可以使用UNSIGNED修飾,使用UNSIGNED修飾之后其不能存儲負值鹏秋,使用的存儲空間不變尊蚁,并且正數(shù)值的存儲范圍擴大了一倍。

22.數(shù)據(jù)的存儲類型決定了該數(shù)據(jù)在內(nèi)存中占用的空間大小侣夷,但是在計算中是使用64位的BIGINT整數(shù)横朋,即使在32位的操作系統(tǒng)中也是如此。

23.可以在整數(shù)類型后指定寬度百拓,如INT(11)琴锭,這種方式指定的是該數(shù)據(jù)在命令行中查詢出來時顯示的位數(shù),而內(nèi)存中使用的位數(shù)是不受影響的衙传。

24.實數(shù)類型:FLOAT决帖,DOUBLE和DECIMAL。前兩種稱為浮點類型蓖捶,對于前兩種MySQL使用浮點數(shù)來存儲地回,因而可能丟失一定的精度,而DECIMAL則使用字符串進行存儲,其不會丟失精度刻像,因而常用于金額的計算畅买。FLOAT占用的存儲空間是4個字節(jié),DOUBLE占用8個字節(jié)细睡,而DECIMAL則可以動態(tài)的指定谷羞,如DECIMAL(18,9)表示小數(shù)點前有9位數(shù)字,小數(shù)點后有9位數(shù)字溜徙,各占4個字節(jié)湃缎,加上小數(shù)點一個字節(jié),總共9個字節(jié)蠢壹,因而DECIMAL相對于浮點數(shù)占用空間更大嗓违。另外,浮點數(shù)只是數(shù)據(jù)庫的存儲方式知残,在計算時還是轉(zhuǎn)換為double類型進行計算靠瞎。

25.如果確認浮點數(shù)的存儲精度,那么可以將浮點數(shù)乘以相應的精度求妹,將其轉(zhuǎn)換為整數(shù),然后使用BIGINT來存儲浮點數(shù)佳窑,這樣可以避免浮點數(shù)精度丟失的問題制恍,并且也可以提高計算效率。

26.varchar的特點:

varchar存儲的是可變長度的字符串神凑,并且其內(nèi)部還會維護1~2個字節(jié)净神,用于存儲實際占用空間的長度;
如果對varchar類型數(shù)據(jù)進行更新溉委,因為新的行比原來的要長鹃唯,因而需要做額外的工作來擴容,并且如果在當前頁沒有更多的空間來存儲瓣喊,這種情況下InnoDB會將當前頁進行分裂以存儲數(shù)據(jù)坡慌,這將導致產(chǎn)生片段數(shù)據(jù),讀取時將造成磁盤的隨機讀寫藻三;
varchar雖說可以根據(jù)實際占用空間來使用硬盤空間洪橘,但是在內(nèi)存中進行計算時,其還是使用聲明的最大長度來存儲數(shù)據(jù)計算的棵帽。
27.char類型是定長的熄求,其適合存儲很短的或者值都接近同一長度的字符串,對于經(jīng)常變更的數(shù)據(jù)逗概,char也比varchar好弟晚,因為char不容易產(chǎn)生碎片。需要注意的是,保存char數(shù)據(jù)時卿城,會將數(shù)據(jù)最后的空格默認給去掉枚钓。

28.BLOB和TEXT類型

BLOB中有TINYBLOB、SMALLBLOB藻雪,BLOB秘噪、MEDIUMBLOB、LONGBLOB勉耀,而TEXT中則同樣有TINYTEXT指煎、SMALLTEXT、TEXT便斥、MEDIUMTEXT至壤、LONGTEXT,這里SMALLBLOB和BLOB是同義詞枢纠,SMALLTEXT和TEXT是同義詞像街;
當BLOB和TEXT值太大時,InnoDB會使用專門的外部存儲區(qū)域進行存儲晋渺,表中字段只需要存儲一個指針镰绎;
BLOB存儲的是二進制數(shù)據(jù),其沒有排序規(guī)則,TEXT存儲的則是字符集,其有排序規(guī)則群凶,并且其只會根據(jù)前max_sort_length長度的字符進行排序颤练;
29.如果數(shù)據(jù)在查詢時使用到了BLOB或者TEXT字段,并且隱式的使用到了臨時表,那么MySQL將使用MyIsam內(nèi)存臨時表,這將造成很大的磁盤開銷。解決辦法有兩個照皆,一是不使用BLOB和TEXT類型,二是在創(chuàng)建BLOB和TEXT字段的時候另外添加一個字段使用substring(column, length)保存BLOB和TEXT類型前面部分數(shù)據(jù)沸停,在進行一些排序操作時使用新加的字段來避免使用MyIsam內(nèi)存臨時表膜毁。這種處理方式也適用于一些存儲值比較長的字段,比如varchar(1000)星立,對于存有1000萬條數(shù)據(jù)的varchar(1000)數(shù)據(jù)爽茴,假設每個字符占3個字節(jié),臨時表的大小將達到30G绰垂。

30.創(chuàng)建枚舉類型字段的方式:

create table enum_test (
e enum ('fish', 'apple', 'dog') not null
);
插入枚舉值的方式:

insert into enum_test (e) values ('apple'), ('dog'), ('fish');
說明:

mysql對于枚舉類型的處理是將其映射為一個整數(shù)值存儲室奏;
如果以枚舉字段排序,那么排序是基于底層映射的枚舉進行的劲装,而不是枚舉字符串胧沫;
31.把值都轉(zhuǎn)換為enum之后昌简,關聯(lián)會變得很快,但是當varchar列和enum列進行關聯(lián)時則慢很多绒怨。但是將列都轉(zhuǎn)換為enum之后由于都映射為了整數(shù)纯赎,因而可以減少表占用的內(nèi)存,這樣可以減少磁盤的I/O南蹂。

32.Mysql有兩種存儲時間的類型:datetime和timestamp犬金。其中datetime與時區(qū)無關,其將時間封裝到格式為YYYYMMDDHHMMSS的整數(shù)中六剥;而timestamp則保存了從1970年1月1日午夜以來的秒數(shù)晚顷。需要注意的是Mysql對時間的處理都是以秒為單位的,如果需要處理毫秒級別的數(shù)據(jù)疗疟,可以使用BIGINT或者DOUBLE類型该默。

33.對于BIT類型,MyISAM會將BIT列數(shù)據(jù)打包存儲在單個字節(jié)中策彤,比如九個BIT位可以保存在兩個字節(jié)中栓袖;而InnoDB則不會打包BIT位數(shù)據(jù),對于每一個BIT位店诗,其都通過一個足夠存儲的最小整數(shù)類型來存放裹刮,所以不能節(jié)省空間。

34.MySQL底層使用字符串保存BIT類型數(shù)據(jù)庞瘸,因而如果直接查詢BIT類型的數(shù)據(jù)時必指,獲得的將是該二進制值轉(zhuǎn)換為整數(shù)后的ascii碼對應的字符串,這是比較令人費解的恕洲,因而對于大部分應用,應該避免使用這種類型梅割。

35.一種保存TRUE/FALSE的方式是使用長度為0的字符串char(0)來表示TRUE霜第,使用NULL值表示FALSE。

36.當某個字段被用作關聯(lián)列的時候户辞,要確保該字段在所有的關聯(lián)表中都使用相同的類型泌类,類型之間要精確匹配,包括像unsigned這樣的屬性底燎。這樣做的目的主要有一個:

避免隱式的類型轉(zhuǎn)換導致的錯誤
37.在可以滿足值的范圍的需求刃榨,并且預留未來增長空間的前提下,應該選擇最小的數(shù)據(jù)類型双仍。這樣做的目的有兩個:

節(jié)省內(nèi)存空間枢希;
更合適的類型能夠提升查詢效率;
38.使用隨機字符串作為關聯(lián)鍵的缺點:

插入值會隨機的分部在索引的任何位置朱沃,因而插入語句會比較慢苞轿;
由于邏輯上相鄰的行會分部在磁盤和內(nèi)存的不同地方茅诱,造成磁頭的隨機讀,因而查詢語句會比較慢搬卒;
造成緩存的效果變差瑟俭,隨機值會造成緩存的局部性原理失效。如果所有的數(shù)據(jù)都一樣“熱”契邀,那么緩存任何一部分特定數(shù)據(jù)導內(nèi)存都沒有好處摆寄;如果工作集比內(nèi)存大,緩存將會有很多刷新和不命中坯门。
39.特殊數(shù)據(jù)類型:

低于秒級精度的時間戳在映射到數(shù)據(jù)庫時需特殊處理微饥,因為datetime和timestamp都是以秒為基本單位;
IPv4地址實際是一個32位無符號整數(shù)田盈,應該使用無符號整數(shù)類型存儲畜号,而不是字符串,MySQL提供了INET_ATON()和INET_NTOA()函數(shù)來將ip地址與字符串進行轉(zhuǎn)換允瞧。
40.太多的列將會導致CPU運行占用非常高简软,查詢效率低下。這是因為MySQL在從存儲引擎層讀取數(shù)據(jù)之后將編碼過的列轉(zhuǎn)換為行數(shù)據(jù)結構的操作代價非常的高述暂,尤其是可變長度的數(shù)據(jù)結構痹升,因而查詢導致需要轉(zhuǎn)碼過多的數(shù)據(jù)。解決辦法是將表按字段進行拆分畦韭,將“熱”字段與“冷”字段分別放在不同的表中疼蛾。

41.MySQL規(guī)定每個關聯(lián)操作最多只能有61張表,但實際上就算少于61張表艺配,關聯(lián)查詢效率也會非常低察郁,單個查詢最好在12個表以內(nèi)進行。

42.Mysql會在索引中存儲null值转唉。

43.范式的優(yōu)點:

范式化的更新操作通常比反范式化要快皮钠;
當數(shù)據(jù)較好地范式化時,就只有很少或者沒有重復數(shù)據(jù)赠法,所以只需修改更少的數(shù)據(jù)麦轰;
范式化的表通常更小,可以更好地放在內(nèi)存里砖织,所以執(zhí)行操作會很快款侵;
很少有多余的數(shù)據(jù)意味著檢索列表數(shù)據(jù)時更少需要distinct或者group by語句。
44.范式的缺點:

查詢時通常需要關聯(lián)侧纯。
45.反范式的優(yōu)點:

減少了表的關聯(lián)操作新锈,這將減少磁盤隨機I/O的次數(shù);
能夠?qū)⒈緫直淼淖侄畏旁谝粋€表中茂蚓,并為其創(chuàng)建索引壕鹉,提高查詢速度剃幌。
46.對于反范式緩存的字段,其與真實字段數(shù)據(jù)的同步可以使用觸發(fā)器進行晾浴。

47.對于需要實時查詢的數(shù)據(jù)负乡,可以通過分段的策略來進行查詢,比如查詢用戶過去一天內(nèi)發(fā)送消息的總數(shù)脊凰,可以將這個查詢操作分為兩部分:過去整個小時時間段內(nèi)發(fā)送消息的數(shù)目和不足一小時的時間段發(fā)送消息的數(shù)目抖棘。而整小時時間段發(fā)送消息的數(shù)目可以通過定時任務同步更新到一張緩存表中,每次查詢同時從緩存表和消息表中分別查詢即可狸涌。

48.在項目中經(jīng)常需要使用一種計數(shù)器切省,比如統(tǒng)計某個鏈接的點擊次數(shù),這里的問題在于每次點擊調(diào)用接口的時候都會對計數(shù)器加一個全局的互斥鎖帕胆,這樣效率非常低朝捆,可以用如下辦法處理該問題,即為該計數(shù)器聲明一個類型懒豹,并且提前創(chuàng)建100條該類型的數(shù)據(jù)芙盘,點擊時通過如下SQL語句更新點擊次數(shù):

UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND() * 100;
并且通過下面的sql語句獲取總的點擊次數(shù):

SELECT SUM(cnt) FROM hit_counter;
如果需要每隔一段時間開始一個計數(shù)器,比如記錄每天的點擊次數(shù)脸秽,那么可以為計數(shù)表聲明一個date和slot字段儒老,建表語句如下:

create table daily_hit_counter (
day date not null,
slot tinyint unsigned not null,
count int unsigned not null,
primary key(day, slot)
) engine=InnoDB;
由于這里為day和slot聲明了唯一索引,因而更新點擊次數(shù)的時候可以通過如下SQL語句進行:

insert into daily_hit_counter (day, slot, count) values (current_date, rand() * 100, 1) on duplicate key update count = count + 1;
49.大部分alter table操作都將導致MySQL的服務中斷记餐,這是因為在執(zhí)行alter table操作的時候MySQL會使用新的schema來創(chuàng)建一個表驮樊,然后將原表的數(shù)據(jù)復制到新表,并且刪除原表片酝。有兩種方式處理alter table過程中鎖表的問題:

在一臺不提供服務的機器上執(zhí)行alter table操作囚衔,然后和提供服務的主庫進行切換;
使用另外一個名稱創(chuàng)建一個“影子表”雕沿,然后通過重命名和刪除表操作來交換兩張表佳魔;
對于列的默認值修改,可以通過兩種方式來避免上述交換表的方式:

修改表的.frm文件中的默認值
通過alter column來更改默認值晦炊,該命令直接修改.frm文件而不設計表數(shù)據(jù),如
alter table sakila.film alter column rental_duration set default 5;

50.MySQL使用索引的原則:

全值匹配:即按順序和索引中的所有列進行匹配宁脊;
匹配最左前綴:即聯(lián)合索引為A断国,B,C為順序的榆苞,那么包含最左邊列的子列集合都會使用到索引稳衬;
匹配列前綴:可以匹配某一列的值的開頭部分,如like 'hellen%'坐漏;
匹配范圍值:可以查詢某一范圍段的值薄疚;
精確匹配某一列并范圍匹配另外一列:在匹配到某一列的值之后可以范圍性的匹配聯(lián)合索引下一列的值碧信;
只訪問索引的查詢:查詢只需要訪問索引,而無需訪問數(shù)據(jù)行街夭。
51.因為索引樹是有序的砰碴,因而在可以使用到索引樹的情況下也可以按照其進行排序。

52.B樹索引的限制:

如果不是按照索引的最左列開始查找板丽,則無法使用索引呈枉;
不能跳過索引中的列進行查找;
如果查詢中有某個列的范圍查詢埃碱,那么其右邊的列都無法使用索引優(yōu)化查找猖辫,這里如果使用了范圍的列的值范圍有限,可以通過多個等于條件代替砚殿,那么也是可以使用索引的啃憎。
53.hash索引是基于hash表實現(xiàn),其多索引列的每個值計算一個hash碼似炎,該hash碼比較小辛萍,然后將hash碼存于索引中,并且將hash碼與相應的數(shù)據(jù)行關聯(lián)起來名党,需要注意的是在hash索引中存儲的順序是按照hash碼有序排序的叹阔。

54.hash索引的限制:

哈希索引只包含哈希值和行指針,而不存儲字段值传睹,所以不能使用索引中的值來避免讀取行耳幢;
哈希索引數(shù)據(jù)并不是按照索引的值的順序存儲的,所以無法用于排序欧啤;
哈希索引也不支持部分索引列匹配查找睛藻,因為哈希索引始終是使用索引列的全部內(nèi)容來計算哈希值的;
哈希索引只支持等值比較查詢邢隧,包括=店印、IN()、<=>倒慧,也不支持任何范圍查詢按摘;
訪問哈希索引的數(shù)據(jù)非常快纫谅,除非有很多哈希沖突炫贤,當有哈希沖突時,存儲引擎必須遍歷鏈表中所有的行指針付秕,逐行進行比較兰珍,知道找到所有符合條件的行;
如果哈希沖突很多的話询吴,一些索引維護操作的代價會很高掠河。
55.InnoDB有一種功能稱為“自適應哈希索引”亮元,當InnoDB發(fā)現(xiàn)某些索引值被使用得非常頻繁時,其會在B-Tree索引的基礎上為這些“熱值”創(chuàng)建的一個哈希索引唠摹,比如根據(jù)某個值作為條件進行查詢的時候其首先會計算該查詢值的hash值爆捞,并且通過該hash值找到對應的列。注意這是一個完全自動的跃闹、內(nèi)部的行為嵌削,用戶無法控制或者配置。

56.當進行某些長字段值的查詢時望艺,我們可以模擬“自適應hash索引”的方式進行查詢苛秕。比如表中存有大量的url,并且需要根據(jù)url進行查詢找默,因為url長度都很長艇劫,并且根據(jù)url進行查詢即使建有索引也會很慢,因而可以為url計算一個hash值惩激,并且新增一個字段店煞,將該hash值存儲在該字段中,另外還需要為該字段創(chuàng)建一個索引风钻,在進行url查詢的時候可以根據(jù)url的hash值查詢新增字段的值顷蟀,由于建有索引,因而該查詢是非陈饧迹快的鸣个,查詢?nèi)缦拢?/p>

select id from pseudohash where url_crc=CRC32("http://www.mysql.com") and url='http://www.mysql.com';
需要注意的是,在使用hash索引的時候還需要將真實值也帶上布朦,因為hash值可能會存在沖突的情況囤萤,帶上真實值可以保證返回唯一的結果。對于url_crc字段的更新可以使用觸發(fā)器完成是趴,如創(chuàng)建如下觸發(fā)器:

CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW SET new.url_crc=crc32(new.url); DELIMITER ;
CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW SET new.url_crc=crc32(new.url);DELIMITER ;
另外涛舍,如果表的數(shù)據(jù)量非常大,可以考慮自己實現(xiàn)一個簡單的64位hash函數(shù)唆途,該函數(shù)返回一個整數(shù)富雅,注意不要使用SHA1()或MD5()作為哈希函數(shù),因為這兩個函數(shù)生成的哈希值本身就是非常長的字符串肛搬。

57.索引的優(yōu)點:

索引大大減少了服務器需要掃描的數(shù)據(jù)量吹榴;
索引可以幫助服務器避免排序和臨時表;
索引可以將隨機I/O變?yōu)轫樞騃/O滚婉。
58.查詢的“三星系統(tǒng)”:索引將相關的記錄放到一起則獲得異性;如果索引中的數(shù)據(jù)順序和查找中的排列順序一致則獲得二星帅刀;如果索引中的列包含了查詢中需要的全部列則獲得三星让腹。

59.只有當索引幫助存儲引擎快速查找到記錄帶來的好處大于其帶來的額外工作時远剩,索引才是有效的。對于非常小的表骇窍,大部分情況下簡單的全表掃描更高效瓜晤;對于中到大型的表,索引就非常有效腹纳;對于特大型的表痢掠,建立和使用索引的代價將隨之增長,這種情況下嘲恍,則需要一種技術可以直接區(qū)分查詢需要的一組數(shù)據(jù)足画,而不是一條記錄一條記錄的匹配,例如可以使用分區(qū)技術佃牛。

60.高性能索引的策略:

①如果查詢的列不是獨立的淹辞,比如索引列在表達式或者是函數(shù)的參數(shù)等,這樣是不會使用索引的俘侠,如:

select actor_id from sakila.actor where actor_id + 1 = 5;
②前綴索引和索引選擇性象缀,比如需要索引的是一個較長的字符串,那么有兩種方式可以解決索引問題:一是通過為每個值生成一個hash值爷速,存于一個新的字段中央星,并創(chuàng)建索引;另一種是只取該字符串的前綴部分惫东,將其存于新字段中莉给,并創(chuàng)建索引。

61.索引合并即表中有多個單列索引凿蒜,在查詢時同時使用到這幾個單列索引禁谦,索引合并具體有以下幾種情況:

or條件的聯(lián)合;
and條件的相交废封;
組合前兩種情況的聯(lián)合及相交州泊;
比如如下示例:

select film_id, actor_id from film_actor where actor_id=1 or film_id=1;
假設film_id和actor_id各自建立了一個索引,在MySQL5.0版本之前該查詢不會使用到任何索引漂洋,但是可以通過如下方式改寫:

select film_id, actor_id from film_actor where actor_id=1 union all film_id=1
使用union all之后MySQL會單獨使用索引進行查詢遥皂,查詢完畢之后將結果集進行合并。在MySQL5.0之后的版本中刽漂,對于前面一條語句演训,其內(nèi)部會自動使用索引合并策略,即使用各自使用單條索引查詢之后進行合并贝咙。同理样悟,對于and條件的相交和組合聯(lián)合及相交的情況和這里講的聯(lián)合的情況類似。

62.索引合并策略部分時候是一種優(yōu)化的結果,但是大部分時候都說明表上索引建得很糟糕:

當出現(xiàn)服務器對多個索引相交操作時(通常有多個and條件)窟她,通常說明需要一個包含所有相關列的多列索引陈症,而不是多個獨立的單列索引;
當服務器需要對多個索引做聯(lián)合操作時(通常有多個or條件)震糖,通常需要耗費大量CPU和內(nèi)存在算法的緩存录肯、排序和合并操作上。特別是當其中有些索引的選擇性不高吊说,需要合并掃描返回的大量數(shù)據(jù)的時候论咏;
優(yōu)化器不會把結果集的合并計算到“查詢成本”中,優(yōu)化器只關心隨機頁面讀取颁井,并且這樣做可能還會影響到查詢的并發(fā)性厅贪。
63.計算前綴索引長度的方式:前綴索引選取的一個標準是索引的選擇性較高(索引的選擇性是指不重復的索引只和數(shù)據(jù)表的記錄總數(shù)的比值)。在選擇索引長度的時候可以通過如下SQL語句進行判斷:

select
count(distinct left(city,3))/count() as sel3,
count(distinct left(city,4))/count(
) as sel4,
count(distinct left(city,5))/count() as sel5,
count(distinct left(city,6))/count(
) as sel6,
count(distinct left(city,7))/count(*) as sel7
from city_demo;
通過該SQL語句分別查詢前綴分別為3蚤蔓,4卦溢,5,6秀又,7列時其選擇性的高低单寂,另外,只看平均選擇性是不夠的吐辙,在選擇性足夠的基礎上還需要查看數(shù)據(jù)分布是否均勻宣决,其可以通過如下SQL語句查看:

select count(*) as cnt, left(city, 7) as pref from city_demo group by pref order by cnt desc limit 5;
最后,創(chuàng)建前綴索引的方式如下:

alter table city_demo add key (city(7));
64.對于索引列的選取昏苏,一般將選擇性最高的列放到索引的最前列尊沸。

65.聚簇索引(InnoDB中)是指將索引和數(shù)據(jù)行存儲到同一個結構中。InnoDB通過主鍵聚集數(shù)據(jù)贤惯。

66.如果沒有定義主鍵洼专,InnoDB會選擇一個唯一的非空索引代替。如果沒有這樣的索引孵构,InnoDB會隱式定義一個主鍵來作為聚簇索引屁商。InnoDB只聚集在同一個頁面中的記錄。包含相鄰鍵值的頁面可能會相距甚遠颈墅。

67.聚簇索引的優(yōu)點:

可以把相關數(shù)據(jù)保存在一起蜡镶,比如通過用戶id來聚集數(shù)據(jù),這樣只需要從磁盤讀取少數(shù)數(shù)據(jù)頁就能獲取用戶的全部郵件恤筛;
數(shù)據(jù)訪問更快官还,因為聚簇索引將索引和數(shù)據(jù)都保存在同一個B-Tree中,因而從聚簇索引中讀取數(shù)據(jù)更快毒坛;
使用覆蓋索引掃描的查詢可以直接使用葉節(jié)點中的主鍵值望伦。
68.聚簇索引的缺點:

聚簇索引最大限度的提高了I/O密集型應用的性能林说,但如果數(shù)據(jù)全部保存在內(nèi)存中,聚簇索引就沒有什么優(yōu)勢屯伞;
插入速度嚴重依賴于插入順序述么。按照主鍵的順序插入是加載數(shù)據(jù)到InnoDB表中速度最快的方式,但如果不是按照主鍵順序加載數(shù)據(jù)愕掏,那么在加載完成之后最好使用OPTIMIZE TABLE命令重新組織一下表;
更新聚簇索引代價很高顶伞,因為會強制InnoDB將每個被更新的行移動到新的位置饵撑;
基于聚簇索引的表在插入新行,或者主鍵被更新導致需要移動行的時候唆貌,可能面臨“頁分裂”的問題滑潘。當行的主鍵值要求必須將一行數(shù)據(jù)插入到某個已滿的頁中時,存儲引擎會將該頁分裂成兩個頁面來容納該行锨咙,這就是一次頁分裂操作语卤,并且頁分裂會導致占用更多的磁盤空間;
聚簇索引可能導致權標掃描變慢酪刀,尤其是行比較稀疏粹舵,或者由于頁分裂導致數(shù)據(jù)存儲不連續(xù)的時候;
二級索引(非聚簇索引)可能比想象的要更大骂倘,因為在二級索引的葉子節(jié)點包含了引用行的主鍵列眼滤;
二級索引訪問需要兩次索引查找,而不是一次历涝,這是因為二級索引中保存的“行指針”不是行的物理位置的指針诅需,而是行的主鍵值。
69.使用隨機聚簇索引的缺點:

寫入的目標頁可能已經(jīng)刷到磁盤上并從緩存中移除荧库,或者是還沒有被加載到內(nèi)存中堰塌,InnoDB在插入之前不得不先找到并從磁盤讀取目標頁到內(nèi)存中,這將導致大量的隨機I/O分衫;
因為寫入是亂序的场刑,InnoDB不得不頻繁地做頁分裂操作,以便為新的行分配空間丐箩。頁分裂會導致移動大量數(shù)據(jù)摇邦,一次插入最少需要修改三個頁而不是一個頁;
由于頻繁地頁分裂屎勘,頁會變得稀疏并被不規(guī)則地填充施籍,所以最終數(shù)據(jù)會有碎片;
70.只有當索引的順序和order by子句的順序完全一致概漱,并且所有列的排序方向(倒序或正序)都一樣時丑慎,MySQL才能夠使用索引來對結果做排序。

71.如果前導列為常量的時候,MySQL才可以在不需要前導列竿裂,并且只按照后續(xù)列的基礎上排序玉吁。

72.壓縮(前綴壓縮)索引的壓縮方式如下:首先保存第一條數(shù)據(jù)的值蝴猪,然后對比第二條數(shù)據(jù)與第一條數(shù)據(jù)前綴部分有多少位相同陪白,將第二位存儲為“位數(shù),后綴”的形式,如第一個值為perform悬槽,第二個值為performance悔常,那么perform將完整保存影斑,而performance的前7位與第一個值相同,其將保存為“7,ance”的形式机打。

73.前綴索引的優(yōu)缺點:

優(yōu)點:由于索引都是有序的矫户,因而前綴相同的概率較大,前綴索引將極大的節(jié)省索引空間残邀;
缺點:前綴索引的每一個值都依賴于前面一個值皆辽,因而前綴索引將無法進行二分查找,并且對于按照正序排序效率尚可芥挣,但是如果按照倒序排序驱闷,效果則不是很好,另外九秀,前綴索引查找某一行平均都要掃描半個索引塊遗嗽。
74.可以在CREATE TABLE語句中指定PACK_KEYS參數(shù)來控制索引壓縮的方式。

75.重復索引是指在相同的列上按照相同的順序創(chuàng)建的相同類型的索引鼓蜒。應該避免這樣創(chuàng)建重復索引痹换,應該立即移除。

76.冗余索引指的是在B-Tree索引中都弹,新創(chuàng)建的索引與某個聯(lián)合索引的前綴部分完全相同的索引娇豫。

77.增加新索引將會導致INSERT、UPDATE畅厢、DELETE等操作的速度變慢冯痢,特別是新增索引后達到內(nèi)存瓶頸的時候。

78.索引可以讓查詢鎖定更少的行框杜,這主要從兩個方面帶來好處:

雖然InnoDB的行鎖效率很高浦楣,內(nèi)存使用很少,但是鎖定行的時候仍然會帶來額外開銷咪辱;
鎖定超過需要的行會增加鎖征用并減少并發(fā)性振劳。
79.在設計索引時,盡可能將需要做范圍查詢的列放到索引的后面油狂,以便優(yōu)化器能夠使用盡可能多的索引列历恐。

80.當需要建的索引列中包含某一列的值是固定的寸癌,比如sex只有male和female兩種,那么這種列可以放在索引的前面弱贼,當需要根據(jù)單個值查詢時直接使用即可蒸苇,如果不需要將該字段作為查詢條件,那么可以通過sex IN ('male', 'female')這種方式來匹配最左前綴吮旅,并且避免該字段的過濾溪烤。

81.對于范圍查詢,比如>庇勃,<氛什,>=,<=等匪凉,使用范圍查詢的字段是可以使用索引的,但是其后續(xù)字段是無法使用索引的捺檬;對于等值查詢再层,等值查詢的字段和其后續(xù)字段都是可以使用索引的。

82.當查詢中存在多個范圍查詢時堡纬,比如需要同時查詢年齡在18到25聂受,并且最近7天登錄的用戶,查詢語句類似如下:

WHERE sex IN ('male', 'female')
AND last_online > DATE_SUB(NOW(), INTERVAL 7 DAY)
AND age BETWEEN 18 AND 25;
這種情況MySQL是無法同時使用兩個字段的索引的烤镐,解決這個問題的方法是考慮新增一個字段蛋济,然后將其中一個字段進行轉(zhuǎn)換,比如新增一個active字段炮叶,由定時任務進行維護碗旅,用戶登錄時,將其設置為1镜悉,并且將過去7天未曾登錄的用戶的值設置為0祟辟。

82.優(yōu)化排序的方式主要分為兩種:

當僅僅只是需要排序的時候,使用索引將排序的字段覆蓋即可侣肄,注意排序的字段排序方式需要一致旧困;
當排序之后使用了limit只進行部分數(shù)據(jù)獲取的時候就需要注意,因為如果查詢的記錄比較靠后稼锅,比如(limit 100000, 10)吼具,那么MySQL會掃描前100010條記錄,并將前100000條記錄丟棄掉矩距,這將耗費大量時間在記錄掃描上(查詢時獲取了過多的列拗盒,因而會掃描每一條的數(shù)據(jù))。解決這個問題的方式在于延遲關聯(lián)剩晴,即首先使用覆蓋索引查詢需要查詢的記錄的id锣咒,然后通過id直接獲取結果集即可侵状,如:
SELECT <cols> FROM profiles INNER JOIN (
SELECT <primary key cols> FROM profiles WHERE x.sex='male' ORDER BY rating LIMIT 100000, 10
) AS x USING(<primary key cols>);
83.可以使用check table <table_name>來檢查表是否損壞,如果存儲引擎不支持check命令毅整,也可以使用alter table來間接修復表趣兄。

84.三種類型的數(shù)據(jù)碎片

行碎片:這種碎片指的是數(shù)據(jù)行被存儲為多個地方的多個片段中,即使查詢只從索引中訪問一行記錄悼嫉,行碎片也會導致性能下降艇潭;
行間碎片:行間碎片是指邏輯上順序的頁,或者行在磁盤上不是順序存儲的戏蔑。行間碎片對注入全表掃描和聚簇索引掃描之類的操作有很大的影響蹋凝,因為這些操作原本能夠從磁盤上順序存儲的數(shù)據(jù)中獲益;
剩余空間碎片:剩余空間碎片是指數(shù)據(jù)頁中有大量的空余空間总棵,這會導致服務器讀取大量不需要的數(shù)據(jù)鳍寂,從而造成浪費。
85.消除碎片化的方式:

執(zhí)行optimize table命令來消除碎片化情龄;
執(zhí)行不做任何操作的alter table命令來重建表迄汛,如alter table <table> engine=<engine>。
86.優(yōu)化低效查詢的通用方式有以下兩種:

確認應用程序是否在檢索大量超過需要的數(shù)據(jù)骤视,這通常意味著太多的行鞍爱,但有時候也可能是訪問了太多列;
確認MySQL服務器層是否在分析大量超過需要的數(shù)據(jù)行专酗。
87.使用“select *”取出全部列會讓優(yōu)化器無法使用索引覆蓋掃描這類優(yōu)化睹逃,還會為服務器帶來額外的I/O、內(nèi)存和CPU的消耗祷肯。

88.衡量MySQL查詢開銷的三個指標:

響應時間沉填;
掃描的行數(shù);
返回的行數(shù)佑笋;
89.MySQL應用where條件的方式有如下三種拜轨,其從好到壞一次為:

在索引中使用where條件來過濾不匹配的記錄。這是在存儲引擎層完成的允青;
使用索引覆蓋掃描(在Extra列中出現(xiàn)了Using Index)來返回記錄橄碾,直接從索引中過濾不需要的記錄并返回命中的結果。這是在MySQL服務器層完成的颠锉,但無需再回表查詢記錄法牲;
從數(shù)據(jù)表中返回數(shù)據(jù),然后過濾不滿足條件的記錄(在Extra列中出現(xiàn)Using where)琼掠。這在MySQL服務器層完成拒垃,MySQL需要先從數(shù)據(jù)表讀取記錄然后過濾。
90.處理MySQL掃描了大量的行瓷蛙,但只需要返回少量數(shù)據(jù)的方案:

使用索引覆蓋掃描悼瓮,把所有需要用的列都放到索引中戈毒,這樣存儲引擎無需會標獲取對應行就可以返回結果了;
該表庫表結構横堡,例如使用單獨的匯總表埋市;
重寫這個復雜的查詢,讓MySQL優(yōu)化器能夠以更優(yōu)化的方式執(zhí)行這個查詢命贴。
91.在其他條件相同的情況下道宅,使用盡可能少的查詢當然是好的,但有的時候胸蛛,將一個大查詢分解為多個小查詢是很有必要的污茵。

92.切分查詢:有時候?qū)⒁粋€大的操作“分而治之”,將大操作切分成小操作葬项,每個操作功能完全一樣泞当,只完成一小部分,這樣雖然延長了處理時間民珍,但是降低了對行或表的鎖定時長零蓉,比如在對日志表數(shù)據(jù)遷移的時候,當遷移完成時需要刪除當前表的數(shù)據(jù)穷缤,如果使用一次delete全部刪除,將導致日志表很長一段時間無法工作箩兽,如果分批完成津肛,比如每次刪除10000條,這將有助于系統(tǒng)更好的工作汗贫。

93.分解關聯(lián)查詢的優(yōu)點:

讓緩存效率更高身坐。因為分解關聯(lián)查詢之后查詢的都是單條記錄,無論是對應用層還是數(shù)據(jù)庫層查詢時都可以直接從緩存中取該數(shù)據(jù)進而查詢其余數(shù)據(jù)落包;
將查詢分解后部蛇,執(zhí)行單個查詢可以減少鎖的競爭;
在應用層做關聯(lián)咐蝇,可以更容易對數(shù)據(jù)庫進行拆分涯鲁,更容易做到高性能和可擴展;
查詢本身效率可能會有所提升有序。因為拆分關聯(lián)查詢之后可以使用in()查詢替代部分數(shù)據(jù)獲取抹腿,這可以讓MySQL按照ID順序進行查詢,其比隨機的關聯(lián)效率更高效旭寿;
可以減少冗余記錄的查詢警绩。在應用層做關聯(lián),意味著對于某條記錄應用只需要查詢一次盅称,而在數(shù)據(jù)庫中做關聯(lián)查詢肩祥,則可能要重復訪問一部分數(shù)據(jù)后室;
這樣做相當于在應用中實現(xiàn)了哈希關聯(lián),而不是使用MySQL的嵌套循環(huán)關聯(lián)混狠。
94.客戶端與服務器之間的通信協(xié)議是“半雙工”的岸霹,這意味著,在任何一個時刻檀蹋,要么是由服務器向客戶端發(fā)送數(shù)據(jù)松申,要么是客戶端向服務器請求數(shù)據(jù),這兩個動作不能同時發(fā)生俯逾。另外贸桶,服務端向客戶端發(fā)送的數(shù)據(jù)一般較多,這個發(fā)送過程是一個推送的過程桌肴,也就是說皇筛,無論客戶端是否停止請求或斷開連接,服務端都會將請求的數(shù)據(jù)完全推送出來坠七。

95.可以通過show full processlist來查看服務器當前狀態(tài)水醋,其主要有以下幾種:

Sleep,線程正在等待客戶端發(fā)送新的請求彪置;
Query拄踪,線程正在執(zhí)行查詢或者正在將結果發(fā)送給客戶端;
Locked拳魁,在MySQL服務器層惶桐,該線程正在等待表鎖;
Analyzing and statistics潘懊,線程正在收集存儲引擎的統(tǒng)計信息姚糊,并生成查詢的執(zhí)行計劃;
Copying to tmp table [on disk]授舟,線程正在執(zhí)行查詢救恨,并且將結果集都復制到一個臨時表中,這種情況一般要么是在做GROUP BY操作释树,要么是文件排序操作肠槽,或者是UNION操作。如果后面還有“on disk”標記奢啥,那表示MySQL正在將一個內(nèi)存臨時表放到磁盤上署浩;
The thread is,線程正在對結果集進行排序扫尺;
Sending data筋栋,線程可能在多個狀態(tài)之間傳送數(shù)據(jù),或者在生成結果集正驻,或者在向客戶端返回數(shù)據(jù)弊攘;
96.在解析一個查詢語句之前抢腐,如果已經(jīng)打開了查詢緩存,那么MySQL首先會在緩存中查看當前查詢是否命中襟交,如果命中了迈倍,并且當前用戶有查詢權限,那么MySQL會跳過其他階段捣域,而直接將當前結果返回啼染。需要注意的是,MySQL查詢緩存是否命中的方式是通過對一個大小寫敏感的哈希查找實現(xiàn)的焕梅,并且其也會將注釋計算在內(nèi)迹鹅。

96.導致MySQL選擇錯誤的執(zhí)行計劃的原因:

統(tǒng)計信息不準確。MySQL依賴存儲引擎提供的統(tǒng)計信息來評估成本贞言,但是有的存儲引擎提供的信息是準確的斜棚,有的偏差可能非常大;
執(zhí)行計劃中的成本估算并不等同于實際執(zhí)行的成本该窗。所以即使統(tǒng)計信息精準弟蚀,優(yōu)化器給出的執(zhí)行計劃也可能不是最優(yōu)的;
MySQL的最優(yōu)可能和你想的最優(yōu)不一樣酗失。MySQL是基于其成本模型選擇的最優(yōu)計劃义钉,有少量時候這并不是最快的執(zhí)行方式;
MySQL從不考慮其他并發(fā)執(zhí)行的查詢规肴,這可能影響到當前查詢的速度捶闸;
MySQL也并不是任何時候都是基于成本的優(yōu)化,而是基于機械固定的規(guī)則奏纪,如存在全文索引的match()子句,則在存在全文索引的時候就使用全文索引斩启;
MySQL不會考慮不受其控制的操作的成本序调,例如存儲過程或者用戶自定義函數(shù)的成本;
優(yōu)化器有的時候無法估算所有可能的執(zhí)行計劃兔簇,所以它可能錯過實際上最優(yōu)的執(zhí)行計劃发绢。
97.MySQL能夠處理的優(yōu)化類型:

重新定義關聯(lián)表的順序。數(shù)據(jù)表的關聯(lián)并不總是按照在查詢中指定的順序執(zhí)行垄琐;
將外鏈接轉(zhuǎn)化成內(nèi)連接边酒。諸多因素,如where條件狸窘、庫表結果都可能會讓外鏈接等價于一個內(nèi)連接墩朦;
使用等價變換規(guī)則。MySQL可以通過一些等價變換來簡化并規(guī)范表達式翻擒;
優(yōu)化count()氓涣、min()和max()牛哺。索引和列是否為空通常可以幫助MySQL優(yōu)化這類表達式劳吠;
預估并轉(zhuǎn)化為常數(shù)表達式引润。當MySQL檢測到一個表達式可以轉(zhuǎn)化為常熟的時候,就會一直把該表達式作為常熟進行優(yōu)化處理痒玩;
覆蓋索引掃描淳附。當索引中的列包含所有查詢中需要使用的列的時候,MySQL就可以使用索引返回需要的數(shù)據(jù)蠢古,而無需查詢對應的數(shù)據(jù)行奴曙;
子查詢優(yōu)化。MySQL在某些情況下可以將子查詢轉(zhuǎn)換成一種效率更高的形式便瑟,從而減少多個查詢多次對數(shù)據(jù)進行訪問缆毁;
提前終止查詢。如果發(fā)現(xiàn)已經(jīng)滿足查詢需求的時候到涂,MySQL總是能夠立即終止查詢脊框,主要有三類:①使用limit子句的時候;②發(fā)現(xiàn)一個不成立的條件践啄,這是MySQL會立刻返回一個空結果浇雹;③在執(zhí)行過程中發(fā)現(xiàn)某些特殊的條件,比如檢索“不同取值”或者判斷存在性(distinct屿讽、not exist()或者left join)時昭灵;
等值傳播。如果兩個列的值通過等式傳播伐谈,那么MySQL能夠把其中一個列的where條件傳遞到另一列上烂完;
列表IN()的比較。沒有是里取會對IN()中的數(shù)據(jù)進行排序诵棵,然后通過二分查找的方式確定列表中的值是否滿足條件抠蚣,這是一個O(log n)的操作,當IN()列表中有大量取值的時候履澳,MySQL的處理速度會更快嘶窄;
98.MySQL進行關聯(lián)查詢的策略:MySQL對任何關聯(lián)都執(zhí)行嵌套循環(huán)關聯(lián)操作,即MySQL先在一個表中循環(huán)取出單條數(shù)據(jù)距贷,然后在嵌套循環(huán)到下一個表中尋找匹配的行柄冲,依次下去,知道找到所有表中匹配的行為止忠蝗。

99.臨時表是沒有索引的现横。

100.MySQL將結果集返回客戶端是一個增量、逐步返回的構成,比如關聯(lián)操作中长赞,一旦服務器處理完最后一個關聯(lián)表晦攒,開始生成第一條結果時,MySQL就開始向客戶端返回結果集了得哆。

101.如果希望union的各個子句能夠根據(jù)limit只取部分結果集脯颜,或者希望能夠先排好序再合并結果集的話,就需要在union的各個子句中分別使用這些子句贩据。另外栋操,從臨時表中取出數(shù)據(jù)的順序并不是一定的,如果想獲得正確的順序饱亮,還需要加上一個全局的order by和limit操作矾芙。

102.在5.0和更新的版本中,當where子句中包含多個復雜條件的時候近上,MySQL能夠訪問單個表的多個索引以合并和交叉過濾的方式來定位需要查找的行剔宪。

103.對于一個IN()列表,如果MySQL優(yōu)化器發(fā)現(xiàn)存在where壹无、on或者using的子句葱绒,將這個列表的值和另一個表的某個列相關聯(lián),那么優(yōu)化器會將IN()列表都復制應用到關聯(lián)的各個表中斗锭。通常地淀,因為各個表新增了過濾條件,優(yōu)化器可以更高效地從存儲引擎過濾記錄岖是。

104.MySQL無法利用多核特性來并行執(zhí)行查詢帮毁。

105.MySQL使用MIN()和MAX()函數(shù)時都是通過全表掃描來獲取匹配的數(shù)據(jù)值的。

106.MySQL不允許在一張表上同時進行查詢和更新豺撑,但是可以為這張表創(chuàng)建一張臨時表烈疚,然后將原表和臨時表進行關聯(lián)來繞開此限制。

107.查詢優(yōu)化器的提示:

HIGH_PRIORITY和LOW_PRIORITY聪轿。HIGH_PRIORITY會將當前當前的SELECT語句放在等待表鎖的語句的最前面爷肝,LOW_PRIORITY會使當前語句處于一直等待的狀態(tài),只要隊列中還有需要訪問同一個表的語句屹电;
DELAYED阶剑。該語句會將使用該提示的語句立即返回給客戶端跃巡,并且將該語句放入緩存危号,待表空閑時再執(zhí)行該語句,其對日志系統(tǒng)或者是客戶端不需要等待其結果的語句非常有效素邪,但是其會導致LAST_INSERT_ID()函數(shù)無法正常工作外莲;
STRAIGHT_JOIN。該提示可以放在SELECT關鍵字之后,也可以放在任何兩個關聯(lián)表的名字之間偷线。放在SELECT之后會讓查詢表的關聯(lián)順序與語句中表出現(xiàn)的順序一致磨确,而放在兩個關聯(lián)表之間會讓查詢這兩個表的關聯(lián)按照其出現(xiàn)的順序進行。該提示對于沒能正確的選擇關聯(lián)順序或者是關聯(lián)順序太多而無法快速選擇時非常有效声邦;
SQL_SMALL_RESULT和SQL_BIG_RESULT乏奥。這兩個語句只對SELECT語句有效,SQL_SMALL_RESULT會告訴優(yōu)化器查詢結果集很小亥曹,可以將結果集放入索引臨時表中邓了,以避免排序操作,而SQL_BIG_RESULT會告訴優(yōu)化器查詢結果集很大媳瞪,可以將結果集放入磁盤臨時表中做排序操作骗炉;
SQL_BUFFER_RESULT。該提示告訴優(yōu)化器將查詢結果放入到一個臨時表中蛇受,然后盡可能快地釋放表鎖句葵;
SQL_CACHE和SQL_NO_CACHE。該提示告訴優(yōu)化器是否將結果集緩存起來兢仰;
SQL_CALC_FOUND_ROWS乍丈。該提示告訴優(yōu)化器對返回的結果集包含更多的信息,比如該提示讓MySQL計算除去LIMIT之后查詢的結果集的總行數(shù)旨别,可以通過FOUND_ROW()獲取這個值诗赌;
FOR UPDATE和LOCK IN SHARE MODE。這兩個提示主要控制SELECT語句的鎖機制秸弛,但只對實現(xiàn)了行級鎖的存儲引擎有效铭若,使用該提示會對符合查詢條件的數(shù)據(jù)行加鎖。需要注意的是递览,這兩個提示會讓某些優(yōu)化無法正常使用叼屠,比如索引覆蓋掃描,應該盡量避免使用這兩個提示绞铃;
USE INDEX镜雨、IGNORE INDEX和FORCE INDEX。這幾個提示會告訴優(yōu)化器使用或者不使用哪些索引進行查詢儿捧,并且在MySQL5.1和之后的版本荚坞,可以使用FOR ORDER BY和FOR GROUP BY來指定是否對排序和分組有效。
108.count()函數(shù)可以統(tǒng)計某個列可用值(不包含NULL)的數(shù)量菲盾,也可以統(tǒng)計行數(shù)颓影,如果在括號中指定了具體的列,那么返回的結果是該列中不包含NULL值的數(shù)據(jù)量懒鉴,如果括號中是或者某個肯定不為NULL的列诡挂,那么返回的將是總行數(shù)碎浇,并且使用COUNT()的時候并不是掃描所有的列以得到統(tǒng)計結果,而是直接獲取總行數(shù)以返回結果璃俗。

109.在使用MyISAM存儲引擎時奴璃,count函數(shù)有時候會比較快,這是因為如果查詢不帶WHERE條件城豁,那么MyISAM可以直接返回總行數(shù)苟穆,否則,其和其他的存儲引擎沒有什么區(qū)別唱星。

110.對于count(*)函數(shù)鞭缭,如果WHERE條件后的條件會導致掃描很大一部分數(shù)據(jù),那么可以考慮將WHERE條件反過來寫魏颓,再使用總數(shù)(因為不帶WHERE條件的統(tǒng)計非沉肜保快)減去該結果即可得到正確結果,如:

SELECT COUNT(*) FROM city WHERE id>5;
其可以改寫為:

SELECT (SELECT COUNT() FROM city) - COUNT() FROM city WHERE id<=5;
111.如果在一條查詢語句中需要統(tǒng)計多個不同條件的數(shù)據(jù)甸饱,可以將COUNT()語句改寫為SUM()語句沦童,比如需要通過一條語句查詢不同顏色商品的數(shù)量,如果單純使用COUNT()語句實現(xiàn)起來比較麻煩叹话,那么可以使用如下SUM()語句:

SELECT SUM(IF(color = 'blue', 1, 0)) AS blue, SUM(IF(color = 'red', 1, 0)) AS red FROM items;
對于COUNT()語句偷遗,由于其是不會統(tǒng)計NULL值的,那么我們也可以利用這一點改寫上述查詢語句:

SELECT COUNT(color = 'blue' OR NULL) AS blue, COUNT(color = 'red' OR NULL) AS red FROM items;
112.在某些業(yè)務場景中并不要求完全精確的COUNT()值驼壶,此時可以使用近似值氏豌,而對于EXPLAIN語句,其在解析SQL語句時統(tǒng)計的時候本身就是一個近似值热凹,并且由于其不會真正執(zhí)行查詢泵喘,因而成本很低菱魔。

113.優(yōu)化關聯(lián)查詢:

確保ON或者USING子句中的列上有索引智厌;
確保任何的GROUP BY和ORDER BY中的表達式只涉及到一個表中的列,這樣MySQL才有可能使用索引來優(yōu)化這個過程屹堰;
當升級MySQL的時候需要注意:關聯(lián)語法碟渺、運算符優(yōu)先級等其他可能會發(fā)生變化的地方鲜锚。因為以前是普通關聯(lián)的地方可能會變成笛卡爾積。
114.對于使用子查詢的時候苫拍,一定要思考是否該子查詢可以改寫為關聯(lián)查詢芜繁,因為即使是相同的執(zhí)行計劃,關聯(lián)查詢大多數(shù)時候都要比子查詢快绒极。

115.如果在關聯(lián)查詢中使用了分組(GROUP BY)骏令,并且是按照某個列進行分組,那么通常采用查找表的標識列(分組列)的效率比其他列更高集峦。

116.在分組查詢語句中直接使用非分組列通常都不是好的主意伏社,因為這樣的結果通常是不定的,或者優(yōu)化器選擇不同的優(yōu)化策略時都會導致結果發(fā)生改變塔淤。

117.如果沒有通過ORDER BY子句顯式地指定排序列摘昌,當查詢使用GROUP BY子句的時候,結果集會自動按照分組的字段進行排序高蜂。如果不關心結果集的順序聪黎,而這種默認排序又導致了需要文件排序,則可以使用ORDER BY NULL备恤,讓MySQL不再進行文件排序稿饰。也可以在GROUP BY子句中直接使用DESC或者ASC關鍵字,使分組的結果集按需要的方向排序露泊。

118.對于LIMIT offset, count翻頁喉镰,其會掃描offset + count條數(shù)據(jù),然后將前offset條數(shù)據(jù)舍棄掉惭笑,當offset比較大的時候侣姆,這將極大的影響查詢效率,比如如下查詢語句:

SELECT film_id, description FROM film ORDER BY title LIMIT 50, 5;
對于這種查詢可以通過三種方式進行改進:

①由于title列建有索引沉噩,因而可以首先在title的使用覆蓋索引獲取第51到55行的數(shù)據(jù)id捺宗,然后通過IN()查詢直接獲取這幾個id的數(shù)據(jù):

SELECT film_id, description FROM film INNER JOIN (SELECT film_id FROM film ORDER BY title LIMIT 50, 5) AS lim ON film.film_id=lim.film_id;
②如何分頁獲取是連續(xù)的,那么可以獲取到上次分頁時的id數(shù)據(jù)川蒙,然后通過WHERE語句過濾掉該id之前或者之后的數(shù)據(jù)蚜厉,這樣就可以通過直接在獲取的數(shù)據(jù)列表的初始或最后獲取所需的數(shù)據(jù),如:

SELECT film_id, description FROM film WHERE id > 14589 ORDER BY title LIMIT 5;
③對于分頁數(shù)據(jù)較大畜眨,用戶一般不會關心較后頁面的數(shù)據(jù)昼牛,這里可以只是展示總的數(shù)據(jù)量,而用戶可點擊的翻頁數(shù)可以限制在一定范圍內(nèi)康聂,比如10000匾嘱,如果用戶確實要獲取某些數(shù)據(jù),其可以進行精確搜索來獲取早抠。

119.表分區(qū)的作用:

表非常大以至于無法放在內(nèi)存中霎烙,或者只在表的最后部分有熱點數(shù)據(jù),其余的均為歷史數(shù)據(jù)蕊连;
分區(qū)表的數(shù)據(jù)更容易維護悬垃;
分區(qū)表的數(shù)據(jù)可以分布在不同的物理設備上,從而高效地利用多個硬件設備甘苍;
可以使用分區(qū)表來避免某些特殊的瓶頸尝蠕,例如InnoDB的單個索引的互斥訪問、ext3文件系統(tǒng)的inode鎖競爭等载庭;
如果需要看彼,還可以備份和恢復獨立的分區(qū)廊佩,這在非常大的數(shù)據(jù)集的場景下效果非常好。
120.分區(qū)表的限制:

一個表最多只能有1024個分區(qū)靖榕;
在MySQL5.1中标锄,分區(qū)表達式必須是整數(shù),或者是返回整數(shù)的表達式茁计,在MySQL5.5中料皇,某些時候可以直接使用列來進行分區(qū);
如果分區(qū)字段中有主鍵或者唯一索引的列星压,那么所有主鍵列和唯一索引列都必須包含進來践剂;
分區(qū)表中無法使用外鍵約束。
121.分區(qū)表的操作原理:

SELECT查詢:當查詢一個分區(qū)表的時候分區(qū)層先打開并鎖住所有的底層表娜膘,優(yōu)化器先判斷是否可以過濾部分分區(qū)逊脯,然后再調(diào)用對應存儲引擎接口訪問各個分區(qū)的數(shù)據(jù);
INSERT操作:當寫入一條記錄時竣贪,分區(qū)層先打開并鎖住所有的底層表男窟,然后確定數(shù)據(jù)對應的分區(qū),最后對相應底層表進行刪除操作贾富;
DELETE操作:當刪除一條記錄時歉眷,分區(qū)層先打開并鎖住所有的底層表,然后確定數(shù)據(jù)對應的分區(qū)颤枪,最后對相應底層表進行刪除操作汗捡;
UPDATE操作:當更新一條記錄時,分區(qū)層先打開并鎖住所有的底層表畏纲,MySQL先確定需要更新的記錄在哪個分區(qū)扇住,然后取出數(shù)據(jù)并更新,再判斷更新后的數(shù)據(jù)應該放在哪個分區(qū)盗胀,最后對底層表進行寫入操作艘蹋,并對原數(shù)據(jù)所在的底層表進行刪除操作。
122.分區(qū)表達式中可以使用各種函數(shù)票灰,但是其返回的值必須是一個確定的整數(shù)女阀,且不能是一個常數(shù)。

123.如下是創(chuàng)建分區(qū)表的一個例子屑迂,該例子中將調(diào)用YEAR()函數(shù)的某一列作為參數(shù)傳入浸策,然后在分區(qū)函數(shù)中通過年份對數(shù)據(jù)進行分區(qū):

CREATE TABLE sales(
order_date DATETIME NOT NULL
)ENGINE =InnoDB PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p_2010 VALUES LESS THAN (2010),
PARTITION p_2011 VALUES LESS THAN (2011),
PARTITION p_2012 VALUES LESS THAN (2012),
PARTITION p_catchall VALUES LESS THAN MAXVALUE
);
124.分區(qū)表的限制:

NULL值會使分區(qū)過濾無效。在分區(qū)函數(shù)進行計算的時候惹盼,所有非法值(如NULL)都會存儲在一個分區(qū)里庸汗,如果該分區(qū)還存儲有正常數(shù)據(jù),那么其數(shù)據(jù)量會比其余的分區(qū)要大手报,并且在進行查詢的時候蚯舱,MySQL會檢查該默認分區(qū)改化,然后再檢查指定的分區(qū),這是由于查詢的時候?qū)⒉樵儣l件的非法值考慮進去了枉昏。解決這個問題的方式是建立一個默認的非法值分區(qū)陈肛,如果數(shù)據(jù)正常,那么該分區(qū)將沒有數(shù)據(jù)凶掰,雖然查詢會掃描兩個分區(qū),但由于該分區(qū)數(shù)據(jù)量較小蜈亩,因而不會產(chǎn)生什么問題懦窘;
分區(qū)列和索引列不匹配。比如分區(qū)列為a稚配,而索引列為b畅涂,那么進行索引查詢的時候由于無法根據(jù)索引確定具體是哪個分區(qū),因而還是需要對每個分區(qū)進行掃描道川。解決這個問題的方式就是將分區(qū)列作為索引列午衰;
選擇分區(qū)的成本可能很高。如果無法確定數(shù)據(jù)具體屬于哪個分區(qū)冒萄,那么掃描數(shù)據(jù)的時候就需要對大部分的分區(qū)進行掃描臊岸,以查找符合條件的數(shù)據(jù),因而建立分區(qū)時需要限制分區(qū)數(shù)量尊流,一般100個左右的分區(qū)是沒有問題的帅戒;
打開并鎖定所有底層表的成本可能很高。在進行查詢時崖技,需要鎖定住所有的分區(qū)表逻住,這一點是在分區(qū)計算的時候進行的,因而無法通過確定分區(qū)來進行優(yōu)化迎献,處理這個問題的方式是盡量使用批量操作瞎访;
維護分區(qū)的成本可能很高。由于每個分區(qū)其實還是一個表吁恍,因而對于創(chuàng)建或刪除分區(qū)其操作比較快扒秸,但是對于修改表結構等操作,那么其和一般的表操作類似冀瓦,也就是說其會先創(chuàng)建一個新的分區(qū)鸦采,然后將舊分區(qū)的數(shù)據(jù)復制到新分區(qū),最后刪除舊分區(qū)咕幻;
所有分區(qū)必須使用相同的存儲引擎渔伯;
分區(qū)函數(shù)中可以使用的函數(shù)表達式也有一些限制;
某些存儲引擎不支持分區(qū)肄程;
對于MyISAM的分區(qū)表锣吼,不能再使用LOAD INDEX INTO CACHE操作选浑;
對于MyISAM表,使用分區(qū)表時需要打開更多的文件描述符玄叠;
125.在進行分區(qū)計算時古徒,MySQL能夠?qū)⒎秶鷹l件轉(zhuǎn)化為離散的值列表,并根據(jù)列表中的每個值過濾分區(qū)读恃。

126.MySQL只能在單純的使用分區(qū)列本身的時候才能過濾分區(qū)隧膘,使用了一些函數(shù),比如YEAR(order_date)寺惫,這種情況下是不能進行分區(qū)的疹吃。

127.在創(chuàng)建分區(qū)時可以使用表達式,但在查詢時缺只能根據(jù)列來過濾分區(qū)西雀。

128.若分區(qū)表是關聯(lián)操作的第二張表萨驶,且關聯(lián)條件是分區(qū)鍵,MySQL就只會在對應的分區(qū)里匹配行艇肴。

129.視圖本身是一個虛擬表腔呜,不存放任何數(shù)據(jù)。

130.可更新視圖是指可以通過更新這個視圖來更新相關的表再悼,只要指定了合適的條件核畴,就可以更新、刪除甚至向視圖中插入數(shù)據(jù)冲九。

131.如果視圖中包含了GROUP BY膛檀、UNION、聚合函數(shù)娘侍,以及其他一些特殊情況咖刃,就不能被更新了。

132.更新視圖的查詢也可以是一個關聯(lián)語句憾筏,但是有一個限制嚎杨,被更新的列必須來自同一個表中,并且所有使用臨時表算法實現(xiàn)的視圖都無法被更新氧腰。

133.在定義視圖時如果使用了CHECK OPTIOIN子句枫浙,這表示所有對視圖的更新都必須符合視圖本身的WHERE條件定義,也即其必須是通過該WHERE條件能夠查詢出來的值古拴。

134.外鍵的優(yōu)點在于能夠保證表數(shù)據(jù)之間的一致性箩帚,其缺點在于在修改一個表的數(shù)據(jù)的時候會隱性的查詢相關聯(lián)的表,這在有的時候會導致一些隱性的表鎖產(chǎn)生黄痪,比如向一個表中插入一條數(shù)據(jù)紧帕,那么相應的會查詢并鎖定父表的相關記錄,這會導致額外的鎖等待,甚至會導致一些死鎖是嗜。

135.在使用外鍵的時候如果目的僅僅是保證數(shù)據(jù)的一致性愈案,那么可以使用觸發(fā)器來替代外鍵,并且外鍵的約束一般在應用程序中進行保證會更好鹅搪。

136.存儲過程的優(yōu)點:

它在服務器內(nèi)部執(zhí)行站绪,離數(shù)據(jù)最近,并且其可以減少語句執(zhí)行的帶寬和網(wǎng)絡延遲丽柿;
這是一種代碼復用恢准,可以為業(yè)務提供統(tǒng)一的業(yè)務規(guī)則,保證某些行為總是一致的甫题;
它能夠簡化代碼的維護和版本的更新馁筐;
它能夠幫助提升安全,比如提供更細粒度的權限控制幔睬;
服務器端可以緩存存儲過程的執(zhí)行計劃眯漩,這對于需要反復調(diào)用的過程芹扭,會大大降低消耗麻顶;
因為是在服務器端部署的,所以備份舱卡、維護都可以在服務器端完成辅肾;
它可以在應用開發(fā)和數(shù)據(jù)庫開發(fā)人員之間更好的分工;
137.存儲過程的缺點:

MySQL沒有提供很好的開發(fā)和調(diào)試工具轮锥,所以編寫MySQL的存儲代碼比其他的數(shù)據(jù)庫要更難些矫钓;
較之應用程序代碼,存儲代碼效率要稍微差些舍杜。這是因為存儲代碼中可供使用的函數(shù)非常少新娜,對于較復雜的邏輯,其比較難處理既绩;
因為存儲程序部署在服務器內(nèi)概龄,因而會存在安全隱患。比如將一些非標準的加密功能放在存儲程序中饲握,那么如果數(shù)據(jù)庫被攻破私杜,數(shù)據(jù)也就被竊取了,如果這些加密功能放在應用程序中救欧,那么攻擊者必須要同時攻破應用程序和數(shù)據(jù)庫才能獲取數(shù)據(jù)衰粹;
存儲程序會給服務器帶來額外的壓力,并且服務器的擴展性較應用程序差很多笆怠;
MySQL沒有提供很好的存儲程序資源消耗的優(yōu)化策略铝耻,因而一個小的錯誤都可能把服務器拖死;
存儲代碼在MySQL中的實現(xiàn)有很多限制蹬刷,如執(zhí)行計劃的緩存是連接級別的田篇,游標的物化和臨時表相同替废,在MySQL5.5版本之前,異常處理也非常困難等等泊柬;
調(diào)試MySQL的存儲過程是一件很困難的事情椎镣;
它和基于語句的二進制日志復制合作得并不好。
138.存儲代碼是一種幫助應用隱藏復雜性兽赁,使得應用開發(fā)更簡便的方法状答,不過它的性能可能更低,而且會給MySQL的復制等增加潛在的風險刀崖。

139.存儲代碼的限制:

優(yōu)化器無法使用關鍵字DETERMINISTIC來優(yōu)化單個查詢中多次調(diào)用存儲函數(shù)的情況惊科;
優(yōu)化器無法評估存儲函數(shù)的執(zhí)行成本;
每個連接都有獨立的存儲過程的執(zhí)行計劃緩存亮钦,如果多個連接需要調(diào)用同一個存儲過程馆截,將會浪費緩存空間來反復緩存同樣的執(zhí)行計劃;
存儲程序和復制是一組詭異的組合蜂莉。如果可以蜡娶,最好不要復制對存儲程序的調(diào)用,直接復制由存儲程序改變的數(shù)據(jù)則會更好映穗。
140.觸發(fā)器可以讓你在執(zhí)行INSERT窖张、UPDATE或者DELETE語句時,執(zhí)行一些特定的操作蚁滋。

141.觸發(fā)器的限制:

對每一個表的每一個事件宿接,最多只能定義一個觸發(fā)器;
MySQL只支持“基于行的出發(fā)”----也就是說辕录,觸發(fā)器始終是針對一條記錄的睦霎,而不是針對整個SQL語句的,如果變更的數(shù)據(jù)集非常大的話走诞,效率會很低副女;
觸發(fā)器可以掩蓋服務器背后的工作,一個簡單的SQL語句背后速梗,因為觸發(fā)器肮塞,可能包含了很多看不見的工作;
觸發(fā)器的問題也很難排查姻锁,如果某個性能問題和觸發(fā)器有關枕赵,會很難分析和定位;
觸發(fā)器可能導致死鎖和鎖等待位隶,如果觸發(fā)器失敗拷窜,那么原來的SQL語句也會失敗。
142.觸發(fā)器并不一定能夠保證原子性。對于MyISAM表篮昧,在執(zhí)行觸發(fā)語句的時候如果遇到問題赋荆,那么原語句是不會回滾的,而對于InnoDB懊昨,觸發(fā)語句和原語句是在同一個事務中的窄潭,如果觸發(fā)語句遇到問題,那么原語句也會回滾酵颁。

143.在使用觸發(fā)器做數(shù)據(jù)約束校驗時需要注意MVCC的作用嫉你。比如當插入一條數(shù)據(jù)時使用觸發(fā)器檢查寫入數(shù)據(jù)的對應列在另一個表中是否存在時,需要使用SELECT FOR UPDATE躏惋,該語句會阻塞更新語句(INSERT幽污、UPDATE和DELETE)直到當前事務提交,比如在觸發(fā)器中檢查某個數(shù)據(jù)值不存在簿姨,隨后就會執(zhí)行插入語句距误,但如果在這中間有另外的語句將數(shù)據(jù)修改為觸發(fā)器所檢查的數(shù)據(jù),那么就會導致錯誤產(chǎn)生扁位。

144.綁定變量的優(yōu)點:

在服務器端只需要解析一次SQL語句准潭;
在服務器端某些優(yōu)化器的工作只需要執(zhí)行一次,因為它會緩存一部分的執(zhí)行計劃贤牛;
以二進制的方式只發(fā)送參數(shù)和句柄惋鹅,比起每次都發(fā)送ASCII碼文本效率更高则酝;
僅僅是參數(shù)--而不是整個查詢語句--需要發(fā)送到服務器端殉簸,所以網(wǎng)絡開銷會更小沽讹;
MySQL在存儲參數(shù)的時候般卑,直接將其存放到緩存中,不再需要在內(nèi)存中多次復制爽雄;
綁定變量也更安全蝠检。
145.MySQL綁定變量的優(yōu)化:

①在準備階段:

服務器解析SQL語句;
②在第一次執(zhí)行的時候

如果可能的話挚瘟,服務器先簡化嵌套循環(huán)的關聯(lián)叹谁,并將外關聯(lián)轉(zhuǎn)化成內(nèi)關聯(lián);
③在每次SQL語句執(zhí)行時

過濾分區(qū)乘盖;
如果可能的話焰檩,盡量移除COUNT()、MIN()和MAX()订框;
移除常數(shù)表達式析苫;
檢測常量表;
做必要的等值傳播;
分析和優(yōu)化ref衩侥、range和索引優(yōu)化等訪問數(shù)據(jù)的方法国旷;
優(yōu)化關聯(lián)順序。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茫死,一起剝皮案震驚了整個濱河市跪但,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌峦萎,老刑警劉巖特漩,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骨杂,居然都是意外死亡涂身,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門搓蚪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛤售,“玉大人,你說我怎么就攤上這事妒潭°材埽” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵雳灾,是天一觀的道長漠酿。 經(jīng)常有香客問我,道長谎亩,這世上最難降的妖魔是什么炒嘲? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮匈庭,結果婚禮上夫凸,老公的妹妹穿的比我還像新娘。我一直安慰自己阱持,他們只是感情好夭拌,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衷咽,像睡著了一般鸽扁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上镶骗,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天桶现,我揣著相機與錄音,去河邊找鬼卖词。 笑死巩那,一個胖子當著我的面吹牛吏夯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播即横,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼噪生,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了东囚?” 一聲冷哼從身側(cè)響起跺嗽,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎页藻,沒想到半個月后桨嫁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡份帐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年璃吧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片废境。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡畜挨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出噩凹,到底是詐尸還是另有隱情巴元,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布驮宴,位于F島的核電站逮刨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏堵泽。R本人自食惡果不足惜修己,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望落恼。 院中可真熱鬧箩退,春花似錦离熏、人聲如沸佳谦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钻蔑。三九已至,卻和暖如春奸鸯,著一層夾襖步出監(jiān)牢的瞬間咪笑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工娄涩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留窗怒,地道東北人映跟。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像扬虚,于是被迫代替她去往敵國和親努隙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 今天看到一位朋友寫的mysql筆記總結辜昵,覺得寫的很詳細很用心荸镊,這里轉(zhuǎn)載一下,供大家參考下堪置,也希望大家能關注他原文地...
    信仰與初衷閱讀 4,734評論 0 30
  • date: 2017-01-12 13:19 來源: inside mysql 微信公眾號 - 最喜歡的mysql...
    daydaygo閱讀 809評論 0 3
  • 一躬存、MySQL優(yōu)化 MySQL優(yōu)化從哪些方面入手: (1)存儲層(數(shù)據(jù)) 構建良好的數(shù)據(jù)結構∫ㄏ牵可以大大的提升我們S...
    寵辱不驚丶歲月靜好閱讀 2,438評論 1 8
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時岭洲,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,320評論 0 9
  • 索引篇 注:使用所有Mysql版本均為Mysql5.5以上坎匿,書上介紹的Mysql版本不超過5.0钦椭,所以書中部分內(nèi)容...
    漫游鷹閱讀 873評論 0 5