MySQL 四種事務(wù)隔離級別以及索引優(yōu)化

一、事務(wù)的基本要素(ACID)

1授滓、原子性(Atomicity):事務(wù)開始后所有操作琳水,要么全部完成肆糕,要么全部不做,不可能停滯在中間環(huán)節(jié)在孝。事務(wù)執(zhí)行過程中出錯诚啃,會回滾到事務(wù)開始前的狀態(tài)。也就是說事務(wù)是一個不可分割的整體私沮。

2始赎、一致性(Consistency):事務(wù)開始前和結(jié)束后,數(shù)據(jù)庫的完整性約束沒有被破壞仔燕,符合所有現(xiàn)實(shí)世界中的約束造垛。例如每一筆交易完成后,都需要保證整個系統(tǒng)的余額等于賬戶的收入減去賬戶的支出晰搀。

3五辽、隔離性(Isolation):同一時間,只允許一個事務(wù)請求同一數(shù)據(jù)外恕,不同的事務(wù)之間彼此沒有任何干擾杆逗。

4、持久性(Durability):事務(wù)完成后鳞疲,事務(wù)對數(shù)據(jù)庫的所有操作都被保存到數(shù)據(jù)庫罪郊,不能回滾。

二尚洽、事務(wù)的并發(fā)問題

1悔橄、臟讀:事務(wù) A 讀取了事務(wù) B 更新的數(shù)據(jù),然后 B 回滾操作翎朱,那么 A 讀取到的數(shù)據(jù)就是臟數(shù)據(jù)橄维。

2、不可重復(fù)讀:事務(wù) A 多次讀取同一數(shù)據(jù)拴曲,事務(wù) B 在事務(wù) A 多次讀取過程中争舞,對數(shù)據(jù)做了更新并提交,導(dǎo)致事務(wù) A 多次讀取同一數(shù)據(jù)時澈灼,結(jié)果不一致竞川。

3、幻讀:事務(wù) A 讀取所有數(shù)據(jù)叁熔,然后事務(wù)B插入了一條數(shù)據(jù)委乌,并且事務(wù)B進(jìn)行了提交。此時事務(wù)A再查詢時荣回,發(fā)現(xiàn)多了一條數(shù)據(jù)遭贸,這就叫幻讀(同一個事務(wù)中多次讀不一樣)。

? ? 小結(jié):不可重復(fù)讀側(cè)重于修改心软,幻讀側(cè)重于新增或刪除壕吹。解決幻讀需要可重復(fù)讀等級以上著蛙。

三、MySQL 事務(wù)隔離級別

MySQL 事務(wù)隔離級別

mysql 默認(rèn)的事務(wù)隔離級別為 repeatable-read

默認(rèn)事務(wù)隔離級別

四耳贬、演示說明各個隔離級別的情況

1踏堡、讀未提交(read-uncommitted):

(1)打開客戶端 A,并設(shè)置當(dāng)前事務(wù)模式為 read uncommitted咒劲,查詢表 goods 的初始值顷蟆;

(2)在客戶端 A 的事務(wù)提交之前,打開另一個客戶端 B腐魂,更新 goods;

(3)這時帐偎,雖然客戶端 B 的事務(wù)還沒提交,但是客戶端 A 就可以查詢到 B 已經(jīng)更新的數(shù)據(jù)挤渔;

(4)一旦客戶端 B 的事務(wù)因?yàn)槟撤N原因回滾肮街,所有的操作都會將被撤銷风题,那客戶端 A 查詢到的數(shù)據(jù)其實(shí)就是臟數(shù)據(jù)判导;

(5)在客戶端 A 執(zhí)行更新語句 update goods set goods_stock = goods_stock - 10 where id =1,iphonex 的 goods_stock沒有變成30沛硅,居然是40眼刃,出現(xiàn)了臟讀。也就是說摇肌,在應(yīng)用程序中擂红,我們會用40-10=30,并不知道其他會話的回滾围小,要想解決這個問題昵骤,可以采用讀已提交的隔離級別。

2肯适、讀已提交(read committed)

(1)打開一個客戶端 A 变秦,并設(shè)置當(dāng)前事務(wù)級別為 read committed,查詢表 goods的初始值框舔;

(2)在客戶端 A 的事務(wù)提交之前蹦玫,打開另一個客戶端 B,更新 goods 刘绣;

(3)這時樱溉,客戶端 B 的事務(wù)還沒提交,客戶端 A 不能查詢到 B 已經(jīng)更新的數(shù)據(jù)纬凤,解決了臟讀的問題福贞;?

(4)客戶端 B 的事務(wù)提交;

(5)客戶端 A 執(zhí)行上一步相同的查詢停士,結(jié)果與上一步不一致挖帘,即產(chǎn)生了不可重復(fù)讀的問題绢馍;

3、可重復(fù)讀(repeatable read)

????一切目的是:保證可重復(fù)讀肠套;A 事務(wù)開啟時舰涌,若A 的讀操作先于 事務(wù)B 的寫操作,則為了可重復(fù)讀你稚,在 A 事務(wù)提交前瓷耙,A事務(wù) 不會將 B 的最新值讀過來;若A 的讀操作晚于 B 的寫操作刁赖,即事務(wù)的首次讀搁痛,會讀取數(shù)據(jù)的最新值。寫操作為了保證數(shù)據(jù)的一致性宇弛,都是會基于最新數(shù)據(jù)操作的鸡典。

(1)打開一個客戶端 A,并設(shè)置當(dāng)前事務(wù)級別為 repeatable read枪芒,查詢表 goods彻况;

(2)在客戶端 A 提交事務(wù)之前,打開另一個客戶端 B舅踪,更新表 goods 并提交纽甘;

(3)客戶端 A 再次執(zhí)行查詢操作,兩次查詢結(jié)果一致抽碌,沒有出現(xiàn)不可重復(fù)讀的問題悍赢;

(4)客戶端 A 接著執(zhí)行 update goods set goods_stock = goods_stock - 10 where id =1,iphonex 的 goods_stock沒有變成50 - 10 = 40货徙,iphonex 的 goods_stock的值用的是步驟(2)中提交的40來算的左权,所以結(jié)果是30,數(shù)據(jù)一致性沒有被破壞痴颊。

(5)客戶端 A 提交事務(wù)赏迟,查詢表 goods;

(6)在客戶端 B 開啟事務(wù)祷舀,新增一條數(shù)據(jù)瀑梗,其中 goods_stock字段值為40,并提交裳扯;

(7) 在客戶端 A 計算 goods_stock 之和抛丽,值為30+50=80,沒有把客戶端 B 的值算進(jìn)去饰豺,客戶端 A 提交后再計算 goods_stock 之和亿鲜,居然變成了120,這是因?yàn)榘芽蛻舳?B 的40算進(jìn)去了;

????對于客戶端 A蒿柳,提交事務(wù)前饶套,多次統(tǒng)計的數(shù)據(jù)沒有變化,故不存在幻讀垒探。

4妓蛮、串行化(serializable)

(1)打開客戶端 A,設(shè)置當(dāng)前事務(wù)級別為?serializable圾叼,查詢表 goods蛤克;

(2)打開一個客戶端B,并設(shè)置當(dāng)前事務(wù)模式為 serializable夷蚊,插入一條記錄報錯构挤,表被鎖了插入失敗。mysql中事務(wù)隔離級別為serializable時會鎖表惕鼓,因此不會出現(xiàn)幻讀的情況筋现,這種隔離級別并發(fā)性極低,開發(fā)中很少會用到箱歧。

補(bǔ)充:

1矾飞、mysql中默認(rèn)的事務(wù)隔離級別是 repeatable? read桥嗤,并不會鎖住讀取到的行;

2牡属、事務(wù)隔離級別為 read committed 時茎刚,寫數(shù)據(jù)只會鎖住相應(yīng)的行。即寫操作鎖住了相應(yīng)的行讨衣,導(dǎo)致讀操作讀不到,故只有寫操作提交了,其他事務(wù)才能讀到最新數(shù)據(jù)输钩;

3、事務(wù)隔離級別為?repeatable? read 時仲智,如果有索引(包括主鍵索引)的時候买乃,以索引列為條件更新數(shù)據(jù),會存在間隙鎖钓辆、行鎖的問題剪验,從而鎖住一些行;如果沒有索引前联,更新數(shù)據(jù)時會鎖住整張表(但是可讀)功戚。

4、隔離級別越高似嗤,越能保證數(shù)據(jù)的完整性和一致性啸臀,但是對并發(fā)性能的影響也越大。對于多數(shù)應(yīng)用程序烁落,可以優(yōu)先考慮隔離級別設(shè)為 Read Committed乘粒,它能夠避免臟讀豌注,而且具有較好的并發(fā)性能。盡管它會導(dǎo)致不可重復(fù)讀灯萍、幻讀這些并發(fā)問題轧铁,在可能出現(xiàn)這類問題的個別場合,可以由應(yīng)用程序采用悲觀鎖或者樂觀鎖來控制旦棉。


多版本并發(fā)控制(MVCC)(快照讀)

多版本并發(fā)控制指的就是在使用READ COMMITTD属桦、REPEATABLE READ這兩種隔離級別的事務(wù)在執(zhí)行普通的 SELECT 操作時訪問記錄的版本鏈的過程,這樣子可以使不同事務(wù)的讀-寫他爸、寫-讀操作并發(fā)執(zhí)行聂宾,從而提升系統(tǒng)性能。

READ COMMITTED —— 每次讀取數(shù)據(jù)前都生成一個新的ReadView.

REPEATABLE READ —— 在第一次讀取數(shù)據(jù)時生成一個ReadView.

普通的 select 就是快照讀诊笤。

select * from T where number = 1;

所以系谐,讀取?ReadView 的時機(jī),便是?READ COMMITTD讨跟、REPEATABLE READ 兩個隔離級別最本質(zhì)的區(qū)別纪他。

Innodb 引擎如何解決幻讀的?

?next-key 鎖

next-key 鎖包含兩部分:

1. 記錄鎖(行鎖)

2. 間隙鎖(gap 鎖)

間隙鎖(Gap Lock):

? ? 定義:鎖加在不存在的空閑空間晾匠,可以是兩個索引記錄之間茶袒,也可能是第一個索引記錄之前或最后一個索引記錄之后的空間。這個 gap 鎖的提出僅僅是為了防止插入幻影記錄而提出的凉馆。

????間隙鎖的出現(xiàn)主要集中在同一個事務(wù)中先 delete 后 insert 的情況下薪寓,當(dāng)我們通過一個索引參數(shù)去刪除一條記錄的時候,如果參數(shù)在數(shù)據(jù)庫中存在澜共,那么這個時候產(chǎn)生的是普通行鎖向叉,鎖住這條記錄,然后刪除嗦董,然后釋放鎖母谎;如果這條記錄不存在,問題就來了京革,數(shù)據(jù)庫會掃描索引奇唤,發(fā)現(xiàn)這個記錄不存在,這個時候的 delete 語句獲取到的就是一個間隙鎖匹摇,然后數(shù)據(jù)庫會掃描到第一個比給定參數(shù)小的值咬扇,向右掃描掃描到第一個比給定參數(shù)大的值,然后以此為界来惧,構(gòu)建一個區(qū)別冗栗,鎖住整個區(qū)間的數(shù)據(jù),一個特別容易出現(xiàn)死鎖的間隙誕生了。

(1)在默認(rèn)的 repeatable read 隔離級別下隅居,并且mysql 存儲引擎是 InnoDB(支持事務(wù)) 時钠至,客戶端 A 開啟事務(wù),執(zhí)行刪除語句 delete from goods where id = 7胎源;

(2)客戶端 B 執(zhí)行 insert into goods (id,goods_name,goods_stock) values (9,"aaaaaa", 80)棉钧,發(fā)現(xiàn)產(chǎn)生了間隙鎖。當(dāng)執(zhí)行刪除語句是涕蚤,由于沒有 id = 7 的記錄宪卿,于是會在id(4 - 10)區(qū)間內(nèi)生成間隙鎖,不允許此區(qū)間內(nèi)的 insert 操作万栅。

??所以佑钾,為了避免間隙鎖,需要遵循存在才刪除原則烦粒,盡量避免刪除不存在的記錄休溶。

除了普通查詢語句,其他的都是當(dāng)前讀(需要加鎖)扰她。

select * from T where number = 1 for update;

select * from T where number = 1 lock in share mode;

insert

update

delete

MySQL 存儲引擎和索引優(yōu)化:

數(shù)據(jù)庫存儲引擎的選擇:

MyISAM:不支持事務(wù)兽掰,表級鎖(讀操作是共享鎖)。適用場景:無事務(wù)場景徒役,只讀場景孽尽。

InnoDB:事務(wù)級存儲引擎,完美支持行級鎖忧勿、事務(wù)ACID特性杉女。MySQL 5.7以上的默認(rèn)選擇。

大事務(wù):在一個事務(wù)中狐蜕,處理了太多的數(shù)據(jù)或者太多的SQL宠纯,導(dǎo)致處理時間很長而產(chǎn)生鎖表。

如何避免大事務(wù)层释?

1、避免一次處理太多的數(shù)據(jù)快集,可以采用分批處理贡羔。

2、移出不必要在事務(wù)中的select操作个初。

索引的選擇:

1乖寒、BTREE索引

BTREE索引,底層是B+樹的實(shí)現(xiàn)方式院溺。

為什么不使用平衡二叉樹做Mysql索引楣嘁?

1、樹的高度決定了它的IO操作次數(shù),而平衡二叉樹由于只有兩個子節(jié)點(diǎn)逐虚,導(dǎo)致樹的高度很高聋溜;

2、每次磁盤IO操作叭爱,可以最多加載一頁的數(shù)據(jù)(即4kb)撮躁,但是它每次只給一個關(guān)鍵字?jǐn)?shù)據(jù),沒有利用好磁盤IO的數(shù)據(jù)交互特性买雾。mysql中每次磁盤IO最多加載16kb把曼。

1.1 B-Tree

B-Tree

B-Tree是一個多路的絕對平衡的查找樹,其關(guān)鍵字(索引)數(shù)量漓穿,一定是小于等于路數(shù)-1嗤军。每個節(jié)點(diǎn)(磁盤塊)都保存了關(guān)鍵字對應(yīng)的數(shù)據(jù),一般是記錄對應(yīng)的磁盤地址晃危。

1.2 B+Tree

B+Tree

B+Tree是B-Tree的Plus版本型雳,它繼承了B-Tree的絕對平衡性。但是山害,B+Tree 的關(guān)鍵字(索引)數(shù)量纠俭,是等于路數(shù)的。并且浪慌,B+Tree的非葉子節(jié)點(diǎn)不保存數(shù)據(jù)相關(guān)信息冤荆,只保存關(guān)鍵字和子節(jié)點(diǎn)的引用。關(guān)鍵字對應(yīng)的數(shù)據(jù)保存在葉子節(jié)點(diǎn)上权纤,其葉子節(jié)點(diǎn)是順序排列的钓简,相鄰節(jié)點(diǎn)具有排序引用的關(guān)系,便于排序和范圍查找汹想。

B+Tree對于B-Tree的優(yōu)勢:

1外邓、B+樹的掃庫、掃表能力更強(qiáng)古掏。因?yàn)樗姆侨~子節(jié)點(diǎn)是不保存數(shù)據(jù)的损话,即能夠保存更多的關(guān)鍵字和子節(jié)點(diǎn)的引用,故掃描更快槽唾。

2丧枪、B+樹的排序能力更強(qiáng)。因?yàn)樗臄?shù)據(jù)全部放在葉子節(jié)點(diǎn)上庞萍,并且是順序排列的(類似鏈表)拧烦。

3、B+樹的查詢效率更加穩(wěn)定钝计。注意:這是并不是說效率更加快恋博,因?yàn)锽+樹的掃描必須掃描到葉子節(jié)點(diǎn)才能拿到數(shù)據(jù)(記錄對應(yīng)的磁盤地址)齐佳,但是B-樹是不需要掃描到葉子節(jié)點(diǎn)就能夠拿到數(shù)據(jù)的。對于相同數(shù)據(jù)量來說债沮,B+樹的高度是比B-樹低的炼吴,所以最壞情況下,B-樹查詢效率比B+樹低秦士。故B+的查詢效率更加穩(wěn)定缺厉。

Mysql中的B+Tree索引體現(xiàn)形式——Myisam:

B+Tree之Myisam

當(dāng)Mysql存儲引擎為Myisam時,其數(shù)據(jù)目錄下會有3個文件:

1隧土、xxx_myisam.frm提针,保存數(shù)據(jù)結(jié)構(gòu);

2曹傀、xxx_myisam.MYD辐脖,保存數(shù)據(jù)(包括每條記錄對應(yīng)的磁盤地址);

3皆愉、xxx_myisam.MYI嗜价,保存索引和條記錄對應(yīng)的磁盤地址。

使用索引查詢時幕庐,會先到.MYI文件查找索引所在的數(shù)據(jù)(磁盤地址)久锥,然后根據(jù)磁盤地址到.MYD文件查找對應(yīng)的數(shù)據(jù)。

Mysql中的B+Tree索引體現(xiàn)形式——Innodb:

Innodb 主鍵索引:

B+Tree之Innodb 主鍵索引

.當(dāng)Mysql存儲引擎為Innodb時异剥,其數(shù)據(jù)目錄下會有2個文件:

1瑟由、xxx_innodb.frm,保存數(shù)據(jù)結(jié)構(gòu)冤寿;

2歹苦、xxx_innodb.ibd,保存數(shù)據(jù)和索引督怜。

上圖是Innodb的主鍵索引:數(shù)據(jù)庫記錄都放在索引葉子節(jié)點(diǎn)上殴瘦,并且是有順序的。只有是主鍵索引才是聚集(密集)索引:數(shù)據(jù)庫表中數(shù)據(jù)的物理順序與索引的順序相同号杠。

此時蚪腋,你會有一個疑問,當(dāng)主鍵為uuid怎么辦究流?

其實(shí)辣吃,我們在建庫的時候,就選擇了數(shù)據(jù)庫的排序規(guī)則為:utf8_general_ci芬探,以ASCII碼,不區(qū)分大小寫的規(guī)則排序厘惦。所以偷仿,我們主鍵采用字符串uuid時哩簿,其會采用ASCII碼進(jìn)行排序,索引分布亦是如此酝静。

Innodb 普通索引:

B+Tree之Innodb 普通索引

普通索引:索引葉子節(jié)點(diǎn)存放是其主鍵的信息节榜,然后根據(jù)主鍵數(shù)據(jù)到主鍵索引中去查詢數(shù)據(jù)記錄。

為什么如此設(shè)計别智?

因?yàn)槠胀ㄋ饕娜~子節(jié)點(diǎn)存放的是主鍵信息宗苍,而主鍵信息一般都不會變的,但是主鍵索引關(guān)聯(lián)的數(shù)據(jù)是整條記錄薄榛,只要記錄發(fā)生變化(如刪除)讳窟,索引就要重新排列。在 Myisam 中敞恋,所有的索引都需要維護(hù)其記錄對應(yīng)的磁盤地址丽啡,性能消耗較大,而 Innodb 中硬猫,只有主鍵索引才需要維護(hù)記錄补箍。

覆蓋索引:如果查詢的列可通過索引直接返回,那么該索引稱之為覆蓋索引啸蜜。

覆蓋索引是不進(jìn)行回表查詢的坑雅,可減少數(shù)據(jù)庫IO,可提高查詢性能衬横。

所以裹粤,不建議查詢直接使用 select * ,因?yàn)檫@樣無法命中覆蓋索引。

密集索引和稀疏索引

密集索引:在密集索引中冕香,文件中的每個搜索碼值都對應(yīng)一個索引值蛹尝。也就是說,密集索引為數(shù)據(jù)記錄文件的每一條記錄都設(shè)一個鍵-指針對悉尾。如下圖所示突那,索引項(xiàng)包括索引值以及指向該搜索碼的第一條數(shù)據(jù)記錄的指針,即我們所說的鍵-指針對构眯。

密集索引圖示

特性:每個存儲塊的每一個鍵對應(yīng)的指針都指向每個數(shù)據(jù)塊每一條記錄愕难,當(dāng)要查找指定鍵K時,采用二分查找即可找到鍵K對應(yīng)的記錄惫霸,復(fù)雜度為log2n猫缭。

稀疏索引:在稀疏索引中,只為搜索碼的某些值建立索引項(xiàng)壹店。也就是說猜丹,稀疏索引為數(shù)據(jù)記錄文件的每個存儲塊設(shè)一個鍵-指針對,存儲塊意味著塊內(nèi)存儲單元連續(xù)硅卢。如下圖所示射窒。

稀疏索引示意圖

特性:每個存儲塊的每一個鍵對應(yīng)的指針都指向每個數(shù)據(jù)塊的第一條記錄藏杖,當(dāng)要查找指定建K時,先采用二分查找找到<=K的鍵S脉顿,如果S=K蝌麸,則命中記錄,如果S<K艾疟,則順序查找=K的鍵来吩,復(fù)雜度大于log2n,小于n蔽莱。

比較:

a??? 稀疏索引占用的索引存儲空間比較小弟疆,但是查找時間較長;

b??? 稠密索引查找時間較短碾褂,索引存儲空間較大兽间。

下面具體看看 Innodb 和 Myisam 索性查詢流程:

索性查詢流程

對于 Myisam 來說,由于它的索引是存放在.MYI文件正塌,數(shù)據(jù)存放在.MYD文件嘀略,在兩個不同的文件上,于是數(shù)據(jù)的查詢必須經(jīng)過兩步乓诽,第一步到索引文件查索引對應(yīng)數(shù)據(jù)的磁盤地址帜羊,第二步根據(jù)磁盤地址拿到數(shù)據(jù),于是其索引都是稀疏索引鸠天。

對于 Innodb 來說讼育,其索引和數(shù)據(jù)都在.ibd文件里,故當(dāng)主鍵查詢時稠集,由于主鍵的葉子節(jié)點(diǎn)直接存放了數(shù)據(jù)奶段,故只要找到了主鍵索引就找到了數(shù)據(jù),故主鍵索引屬于密集索引剥纷。但是對于普通索引來說痹籍,其葉子節(jié)點(diǎn)存儲的是主鍵信息,其查詢需要兩步晦鞋,先到普通索引 Tree 查到主鍵信息蹲缠,然后根據(jù)主鍵信息到主鍵索引 Tree 去查詢記錄。于是 Innodb 必須要有且僅有一個密集索引悠垛,其分配規(guī)則如下:

Innodb 密集索引分配規(guī)則

索引優(yōu)化:

(1)BTREE索引的使用場景:

場景1
場景2

使用場景:

1线定、全值匹配的查詢,如oder_sn='9876432119900'确买;

2斤讥、匹配最左前綴的查詢,在聯(lián)合索引中湾趾,只要最左的索引列用到了周偎,該索引就會生效抹剩。但是如果是后面的索引列用到了撑帖,最左列未使用蓉坎,是不會生效的;

3胡嘿、匹配列前綴查詢蛉艾,即模糊查詢最前面不要使用‘%’,如order_sn='9876%'衷敌;

4勿侯、匹配范圍的查詢,如oder_sn>'9876432119900'缴罗,order_sn<'9876432119999'助琐;

5、精確匹配左前列并范圍匹配另外一列面氓。

(2)BTREE索引的使用限制:

使用限制

使用限制:

1兵钮、如果不是按照索引最左列開始查找的,則無法使用索引舌界;

2掘譬、使用索引時不能跳過索引的列,假如3個列的聯(lián)合索引呻拌,用到了1葱轩、3,未用的2藐握,此時只有1是生效的靴拱,3是不生效的;

3猾普、Not in 和 <> 操作無法使用索引袜炕;

4、如果查詢中有某個列的范圍查找抬闷,則其右邊的所有列都無法使用索引妇蛀。

5、排序列包含非同一個索引的列笤成,也無法使用索引评架。

6、排序列使用了復(fù)雜的表達(dá)式炕泳,如?UPPER(name)纵诞,也無法使用索引。

7培遵、如果索引列在比較表達(dá)式中不是以單獨(dú)列的形式出現(xiàn)浙芙,而是以某個表達(dá)式登刺,或者函數(shù)調(diào)用形式出現(xiàn)的話(如 where age * 2 > 6),是用不到索引的嗡呼。

2纸俭、Hash索引

Hash索引,底層是Hash表南窗。具體Hash表的結(jié)構(gòu)揍很,可以參考我的另一篇文章 Java7/8 中的HashMap 和 ConcurrentHashMap

(1)Hash索引的特點(diǎn):

Hash 索引的特點(diǎn)

只有查詢條件精確匹配Hash索引中的所有列時万伤,才能夠使用到Hash索引窒悔。

Hash索引的限制

Hash索引的限制:

1、Hash索引必須進(jìn)行二次查找敌买,因?yàn)镠ash索引存儲的是Hash碼简珠,并不是直接存儲數(shù)據(jù)的指針地址,所以需要二次查詢虹钮,但是由于數(shù)據(jù)庫都是有緩存的聋庵,這樣的性能損耗可以忽略;

2芜抒、Hash索引無法用于排序珍策,因?yàn)樗幌馚TREE那樣是順序存儲元素的;

3宅倒、Hash索引不支持部分索引查找也不支持范圍查找攘宙,只支持精確查找;

4拐迁、Hash索引中的Hash碼的計算可能存在Hash沖突蹭劈,從而影響性能。

索引優(yōu)化:


聯(lián)合索引優(yōu)化

創(chuàng)建聯(lián)合索引時线召,如何選擇索引列的順序铺韧?

1、經(jīng)常會被使用到的列優(yōu)先缓淹;

2哈打、選擇性高的列優(yōu)先,即值的可能性比較多的列讯壶;

3料仗、寬度小的列優(yōu)選。

order by 優(yōu)化

使用索引掃描來優(yōu)化排序:

1伏蚊、索引的列排序和Order by 子句的順序完全一致立轧;

2、索引中的所有列的方向(升序,降序)和Order by 子句完全一致氛改;

3帐萎、Order by 中的字段全部在關(guān)聯(lián)表的第一張表中。


在mysql種這兩種方式的體現(xiàn)就是加鎖和不加鎖

普通查詢不加鎖使用快照讀

如果在事務(wù)中出了查詢外還有其他增加修改操作那么久要手動加鎖實(shí)現(xiàn)當(dāng)前讀

彩蛋:

mysql 客戶端發(fā)起一條 SQL 到服務(wù)端返回數(shù)據(jù)胜卤,經(jīng)過了哪些流程耕陷?

mysql 處理流程

1. 連接管理:驗(yàn)證用戶名闲孤、密碼是否正確华临。

2. 解析與優(yōu)化

(一)查詢緩存:mysql?會把剛剛處理過的查詢請求和結(jié)果緩存起來僧须,下次如果有同樣的請求過來時,會直接返回緩沖的結(jié)果紫新。如果兩個查詢請求在任何字符上的不同(例如:空格、注釋李剖、大小寫)芒率,都會導(dǎo)致緩存不會命中。另外篙顺,如果查詢請求中包含某些系統(tǒng)函數(shù)偶芍、用戶自定義變量和函數(shù)、一些系統(tǒng)表德玫,如 mysql 匪蟀、information_schema、 performance_schema 數(shù)據(jù)庫中的表宰僧,那這個請求就不會被緩存材彪。系統(tǒng)函數(shù)如:NOW。

雖然查詢緩存有時可以提升系統(tǒng)性能琴儿,但也不得不因維護(hù)這塊緩存而造成一些開銷段化,比如每次都要去查詢緩存中檢索,查詢請求處理完需要更新查詢緩存造成,維護(hù)該查詢緩存對應(yīng)的內(nèi)存區(qū)域显熏。從 MySQL 5.7.20 開始,不推薦使用查詢緩存晒屎,并在 MySQL 8.0 中刪除喘蟆。

(二)語法解析:因?yàn)榭蛻舳顺绦虬l(fā)送過來的請求只是一段文本而已,所以 MySQL 服務(wù)器程序首先要對這段文本做分析鼓鲁,判斷請求的語法是否正確蕴轨。

(三)語法優(yōu)化:因?yàn)槲覀儗懙?MySQL 語句執(zhí)行起來效率可能并不是很高,MySQL 的優(yōu)化程序會對我們的語句做一些優(yōu)化坐桩,如外連接轉(zhuǎn)換為內(nèi)連接尺棋、表達(dá)式簡化、查詢字段順序調(diào)整等。優(yōu)化的結(jié)果就是生成一個執(zhí)行計劃膘螟,這個執(zhí)行計劃表明了應(yīng)該使用哪些索引進(jìn)行查詢成福,表之間的連接順序是啥樣的。

3. 存儲引擎:MySQL 服務(wù)器把數(shù)據(jù)的存儲和提取操作都封裝到了一個叫存儲引擎的模塊里荆残。我們知道表是由一行一行的記錄組成的奴艾,但這只是一個邏輯上的概念,物理上如何表示記錄内斯,怎么從表中讀取數(shù)據(jù)蕴潦,怎么把數(shù)據(jù)寫入具體的物理存儲器上,這都是存儲引擎負(fù)責(zé)的事情俘闯。如 InnoDB潭苞、MyISAM等。

為什么不建議使用 uuid 作為主鍵真朗?

1.?uuid 占用的空間較大

2. uuid 是無序的此疹,作為主引容易導(dǎo)致索引分裂,性能低下遮婶,因?yàn)槿~子節(jié)點(diǎn)需要重新排序蝗碎。如果是自增主鍵,則直接在葉子節(jié)點(diǎn)后面添加即可旗扑。

Explain SQL語句時蹦骑,不同的 type 場景:

const當(dāng)我們根據(jù)主鍵或者唯一二級索引列與常數(shù)進(jìn)行等值匹配時,對單表的訪問方法就是 const臀防。

ref當(dāng)通過普通的二級索引列與常量進(jìn)行等值匹配時來查詢某個表眠菇,那么對該表的訪問方法就可能是 ref。

ref_or_null當(dāng)對普通二級索引進(jìn)行等值匹配查詢清钥,該索引列的值也可以是 NULL 值時琼锋,那么對該表的訪問方法就可能是 ref_or_null。

range如果使用索引獲取某些范圍區(qū)間的記錄祟昭,那么就可能使用到 range 訪問方法缕坎。

index:當(dāng)我們可以使用索引覆蓋,但需要掃描全部的索引記錄時篡悟,該表的訪問方法就是 index谜叹。

all:全表掃描。

一般來說搬葬,這些訪問方法按照我們介紹它們的順序性能依次變差荷腊。其中除了 all 這個訪問方法外,其余的訪問方法都能用到索引急凰,并且只能用到一個索引女仰。

附錄:mysql 各文本字段類型的長度限制:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疾忍,更是在濱河造成了極大的恐慌乔外,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件一罩,死亡現(xiàn)場離奇詭異杨幼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)聂渊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門差购,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人汉嗽,你說我怎么就攤上這事欲逃。” “怎么了诊胞?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵暖夭,是天一觀的道長。 經(jīng)常有香客問我撵孤,道長,這世上最難降的妖魔是什么竭望? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任邪码,我火速辦了婚禮,結(jié)果婚禮上咬清,老公的妹妹穿的比我還像新娘闭专。我一直安慰自己,他們只是感情好旧烧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布影钉。 她就那樣靜靜地躺著,像睡著了一般掘剪。 火紅的嫁衣襯著肌膚如雪平委。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天夺谁,我揣著相機(jī)與錄音廉赔,去河邊找鬼。 笑死匾鸥,一個胖子當(dāng)著我的面吹牛蜡塌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勿负,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼馏艾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起琅摩,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤铁孵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后迫吐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體库菲,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年志膀,在試婚紗的時候發(fā)現(xiàn)自己被綠了熙宇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡溉浙,死狀恐怖烫止,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情戳稽,我是刑警寧澤馆蠕,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站惊奇,受9級特大地震影響互躬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颂郎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一吼渡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乓序,春花似錦寺酪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至陨献,卻和暖如春盒犹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背湿故。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工阿趁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坛猪。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓脖阵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親墅茉。 傳聞我的和親對象是個殘疾皇子命黔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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