MySQL實戰45講學習筆記:第十五講

1、引子

在今天這篇答疑文章更新前,MySQL 實戰這個專欄已經更新了 14 篇。在這些文章中,你們在評論區留下了不少高質量的留言。如今,每篇文章的評論區都有熱心的同窗幫忙總結文章知識點,也有很多同窗提出了不少高質量的問題,更有一些同窗幫忙解答其餘同窗提出的問題。mysql

在瀏覽這些留言並回復的過程當中,我倍受鼓舞,也盡我所知地幫助你解決問題、和你討論。能夠說,大家的留言活躍了整個專欄的氛圍、提高了整個專欄的質量,謝謝大家。評論區的大多數留言我都直接回復了,對於須要展開說明的問題,我都拿出小本子記了下來。這些被記下來的問題,就是咱們今天這篇答疑文章的素材了。sql

到目前爲止,我已經收集了 47 個問題,很難經過今天這一篇文章所有展開。因此,我就先從中找了幾個聯繫很是緊密的問題,串了起來,但願能夠幫你解決關於日誌和索引的一些疑惑。而其餘問題,咱們就留着後面慢慢展開吧。數據庫

2、日誌相關

我在第 2 篇文章《日誌系統:一條 SQL 更新語句是如何執行的?》中,和你講到binlog(歸檔日誌)和 redo log(重作日誌)配合崩潰恢復的時候,用的是反證法,說明
了若是沒有兩階段提交,會致使 MySQL 出現主備數據不一致等問題。緩存

在這篇文章下面,不少同窗在問,在兩階段提交的不一樣瞬間,MySQL 若是發生異常重啓,是怎麼保證數據完整性的?bash

如今,咱們就從這個問題開始吧。session

我再放一次兩階段提交的圖,方便你學習下面的內容。架構

圖 1 兩階段提交示意圖併發

這裏,我要先和你解釋一個誤會式的問題。有同窗在評論區問到,這個圖不是一個update 語句的執行流程嗎,怎麼還會調用 commit 語句?數據庫設計

他產生這個疑問的緣由,是把兩個「commit」的概念混淆了:分佈式

  • 他說的「commit 語句」,是指 MySQL 語法中,用於提交一個事務的命令。通常跟begin/start transaction 配對使用。
  • 而咱們圖中用到的這個「commit 步驟」,指的是事務提交過程當中的一個小步驟,也是最後一步。當這個步驟執行完成後,這個事務就提交完成了。
  • 「commit 語句」執行的時候,會包含「commit 步驟」。

而咱們這個例子裏面,沒有顯式地開啓事務,所以這個 update 語句本身就是一個事務,在執行完成後提交事務時,就會用到這個「commit 步驟「。

接下來,咱們就一塊兒分析一下在兩階段提交的不一樣時刻,MySQL 異常重啓會出現什麼現象

若是在圖中時刻 A 的地方,也就是寫入 redo log 處於 prepare 階段以後、寫 binlog 以前,發生了崩潰(crash),因爲此時 binlog 還沒寫,redo log 也還沒提交,因此崩潰恢復的時候,這個事務會回滾。這時候,binlog 還沒寫,因此也不會傳到備庫。到這裏,你們均可以理解。

你們出現問題的地方,主要集中在時刻 B,也就是 binlog 寫完,redo log 還沒 commit前發生 crash,那崩潰恢復的時候 MySQL 會怎麼處理?

咱們先來看一下崩潰恢復時的判斷規則。

1. 若是 redo log 裏面的事務是完整的,也就是已經有了 commit 標識,則直接提交;
2. 若是 redo log 裏面的事務只有完整的 prepare,則判斷對應的事務 binlog 是否存在並完整:

a. 若是是,則提交事務;
b. 不然,回滾事務。

這裏,時刻 B 發生 crash 對應的就是 2(a) 的狀況,崩潰恢復過程當中事務會被提交。

如今,咱們繼續延展一下這個問題。

追問 1:MySQL 怎麼知道 binlog 是完整的?

回答:一個事務的 binlog 是有完整格式的:

statement 格式的 binlog,最後會有 COMMIT;
row 格式的 binlog,最後會有一個 XID event。

另外,在 MySQL 5.6.2 版本之後,還引入了 binlog-checksum 參數,用來驗證 binlog內容的正確性。對於 binlog 日誌因爲磁盤緣由,可能會在日誌中間出錯的狀況,MySQL能夠經過校驗 checksum 的結果來發現。因此,MySQL 仍是有辦法驗證事務 binlog 的完整性的。

 

追問2:redo log 和 binlog 是怎麼關聯起來的?

 

回答:它們有一個共同的數據字段,叫 XID。崩潰恢復的時候,會按順序掃描 redo log:

  • 若是碰到既有 prepare、又有 commit 的 redo log,就直接提交;
  • 若是碰到只有 parepare、而沒有 commit 的 redo log,就拿着 XID 去 binlog 找對應的事務。

追問 3:處於 prepare 階段的 redo log 加上完整 binlog,重啓就能恢復,MySQL 爲何要這麼設計?

回答:其實,兩階段提交是經典的分佈式系統問題,並非 MySQL 獨有的。若是必需要舉一個場景,來講明這麼作的必要性的話,那就是事務的持久性問題。

回答:其實,這個問題仍是跟咱們在反證法中說到的數據與備份的一致性有關。在時刻B,也就是 binlog 寫完之後 MySQL 發生崩潰,這時候 binlog 已經寫入了,以後就會被從庫(或者用這個 binlog 恢復出來的庫)使用。

因此,在主庫上也要提交這個事務。採用這個策略,主庫和備庫的數據就保證了一致性

追問 4:若是這樣的話,爲何還要兩階段提交呢?乾脆先 redo log 寫完,再寫 binlog。崩潰恢復的時候,必須得兩個日誌都完整才能夠。是否是同樣的邏輯?

回答:其實,兩階段提交是經典的分佈式系統問題,並非 MySQL 獨有的。

若是必需要舉一個場景,來講明這麼作的必要性的話,那就是事務的持久性問題。

對於 InnoDB 引擎來講,若是 redo log 提交完成了,事務就不能回滾(若是這還容許回滾,就可能覆蓋掉別的事務的更新)。而若是 redo log 直接提交,而後 binlog 寫入的

兩階段提交就是爲了給全部人一個機會,當每一個人都說「我 ok」的時候,再一塊兒提交。


追問 5:不引入兩個日誌,也就沒有兩階段提交的必要了。只用 binlog 來支持崩潰恢復,又能支持歸檔,不就能夠了?

回答:這位同窗的意思是,只保留 binlog,而後能夠把提交流程改爲這樣:… -> 「數據更新到內存」 -> 「寫 binlog」 -> 「提交事務」,是否是也能夠提供崩潰恢復的能力?
答案是不能夠。

若是說歷史緣由的話,那就是 InnoDB 並非 MySQL 的原生存儲引擎。MySQL 的原生引擎是 MyISAM,設計之初就有沒有支持崩潰恢復。

InnoDB 在做爲 MySQL 的插件加入 MySQL 引擎家族以前,就已是一個提供了崩潰恢復和事務支持的引擎了。

InnoDB 接入了 MySQL 後,發現既然 binlog 沒有崩潰恢復的能力,那就用 InnoDB 原有的 redo log 好了。

而若是說實現上的緣由的話,就有不少了。就按照問題中說的,只用 binlog 來實現崩潰恢復的流程,我畫了一張示意圖,這裏就沒有 redo log 了。

圖 2 只用 binlog 支持崩潰恢復


這樣的流程下,binlog 仍是不能支持崩潰恢復的。我說一個不支持的點吧:binlog 沒有能力恢復「數據頁」。

若是在圖中標的位置,也就是 binlog2 寫完了,可是整個事務尚未 commit 的時候,MySQL 發生了 crash。

重啓後,引擎內部事務 2 會回滾,而後應用 binlog2 能夠補回來;可是對於事務 1 來講,系統已經認爲提交完成了,不會再應用一次 binlog1。

可是,InnoDB 引擎使用的是 WAL 技術,執行事務的時候,寫完內存和日誌,事務就算完成了。若是以後崩潰,要依賴於日誌來恢復數據頁。

也就是說在圖中這個位置發生崩潰的話,事務 1 也是可能丟失了的,並且是數據頁級的丟失。此時,binlog 裏面並無記錄數據頁的更新細節,是補不回來的。

你若是要說,那我優化一下 binlog 的內容,讓它來記錄數據頁的更改能夠嗎?但,這其實就是又作了一個 redo log 出來。

因此,至少如今的 binlog 能力,還不能支持崩潰恢復。

追問 6:那能不能反過來,只用 redo log,不要 binlog?

回答:若是隻從崩潰恢復的角度來說是能夠的。你能夠把 binlog 關掉,這樣就沒有兩階段提交了,但系統依然是 crash-safe 的。

可是,若是你瞭解一下業界各個公司的使用場景的話,就會發如今正式的生產庫上,binlog 都是開着的。由於 binlog 有着 redo log 沒法替代的功能。

一個是歸檔。redo log 是循環寫,寫到末尾是要回到開頭繼續寫的。這樣歷史日誌無法保留,redo log 也就起不到歸檔的做用。

一個就是 MySQL 系統依賴於 binlog。binlog 做爲 MySQL 一開始就有的功能,被用在了不少地方。其中,MySQL 系統高可用的基礎,就是 binlog 複製。

還有不少公司有異構系統(好比一些數據分析系統),這些系統就靠消費 MySQL 的binlog 來更新本身的數據。關掉 binlog 的話,這些下游系統就無法輸入了。

總之,因爲如今包括 MySQL 高可用在內的不少系統機制都依賴於 binlog,因此「鳩佔鵲巢」redo log 還作不到。你看,發展生態是多麼重要。


追問 7:redo log 通常設置多大?

回答:redo log 過小的話,會致使很快就被寫滿,而後不得不強行刷 redo log,這樣WAL 機制的能力就發揮不出來了。

因此,若是是如今常見的幾個 TB 的磁盤的話,就不要過小氣了,直接將 redo log 設置爲4 個文件、每一個文件 1GB 吧。

追問 8:正常運行中的實例,數據寫入後的最終落盤,是從 redo log 更新過來的仍是從 buffer pool 更新過來的呢?


回答:這個問題其實問得很是好。這裏涉及到了,「redo log 裏面究竟是什麼」的問題。

實際上,redo log 並無記錄數據頁的完整數據,因此它並無能力本身去更新磁盤數據頁,也就不存在「數據最終落盤,是由 redo log 更新過去」的狀況。

1. 若是是正常運行的實例的話,數據頁被修改之後,跟磁盤的數據頁不一致,稱爲髒頁。最終數據落盤,就是把內存中的數據頁寫盤。這個過程,甚至與 redo log 毫無關係。

2. 在崩潰恢復場景中,InnoDB 若是判斷到一個數據頁可能在崩潰恢復的時候丟失了更新,就會將它讀到內存,而後讓 redo log 更新內存內容。更新完成後,內存頁變成髒頁,就回到了第一種狀況的狀態。

追問 9:redo log buffer 是什麼?是先修改內存,仍是先寫 redo log文件?

回答:這兩個問題能夠一塊兒回答。

在一個事務的更新過程當中,日誌是要寫屢次的。好比下面這個事務:

begin;
insert into t1 ...
insert into t2 ...
commit;

這個事務要往兩個表中插入記錄,插入數據的過程當中,生成的日誌都得先保存起來,但又不能在還沒 commit 的時候就直接寫到 redo log 文件裏。

因此,redo log buffer 就是一塊內存,用來先存 redo 日誌的。也就是說,在執行第一個insert 的時候,數據的內存被修改了,redo log buffer 也寫入了日誌。

可是,真正把日誌寫到 redo log 文件(文件名是 ib_logfile+ 數字),是在執行 commit語句的時候作的。

(這裏說的是事務執行過程當中不會「主動去刷盤」,以減小沒必要要的 IO 消耗。可是可能會出現「被動寫入磁盤」,好比內存不夠、其餘事務提交等狀況。這個問題咱們會在後面第 22 篇文章《MySQL 有哪些「飲鴆止渴」的提升性能的方法?》中再詳細展開)。

單獨執行一個更新語句的時候,InnoDB 會本身啓動一個事務,在語句執行完成的時候提交。過程跟上面是同樣的,只不過是「壓縮」到了一個語句裏面完成。

以上這些問題,就是把你們提過的關於 redo log 和 binlog 的問題串起來,作的一次集中回答。若是你還有問題,能夠在評論區繼續留言補充。

3、業務設計問題

接下來,我再和你分享 @ithunter 同窗在第 8 篇文章《事務究竟是隔離的仍是不隔離的?》的評論區提到的跟索引相關的一個問題。我以爲這個問題挺有趣、也挺實用的,其餘同窗也可能會碰上這樣的場景,在這裏解答和分享一下。

問題是這樣的(我文字上稍微作了點修改,方便你們理解):

業務上有這樣的需求,A、B 兩個用戶,若是互相關注,則成爲好友。設計上是有兩張表,一個是 like 表,一個是 friend 表,like 表有 user_id、liker_id 兩個字段,我設置爲複合惟一索引即 uk_user_id_liker_id。語句執行邏輯是這樣的:

以 A 關注 B 爲例:
第一步,先查詢對方有沒有關注本身(B 有沒有關注 A)
select * from like where user_id = B and liker_id = A;

若是有,則成爲好友
insert into friend;

沒有,則只是單向關注關係
insert into like;

可是若是 A、B 同時關注對方,會出現不會成爲好友的狀況。由於上面第 1步,雙方都沒關注對方。第 1 步即便使用了排他鎖也不行,由於記錄不存在,行鎖沒法生效。請問這種狀況,在 MySQL 鎖層面有沒有辦法處理?

首先,我要先贊一下這樣的提問方式。雖然極客時間如今的評論區還不能追加評論,但若是你們可以一次留言就把問題講清楚的話,其實影響也不大。因此,我但願你在留言提問的時候,也能借鑑這種方式。

接下來,我把 @ithunter 同窗說的表模擬出來,方便咱們討論。

CREATE TABLE `like` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `liker_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id_liker_id` (`user_id`,`liker_id`)
) ENGINE=InnoDB;

CREATE TABLE `friend` (
  id` int(11) NOT NULL AUTO_INCREMENT,
  `friend_1_id` int(11) NOT NULL,
  `firned_2_id` int(11) NOT NULL,
  UNIQUE KEY `uk_friend` (`friend_1_id`,`firned_2_id`)
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

雖然這個題幹中,並無說到 friend 表的索引結構。但我猜想 friend_1_id 和friend_2_id 也有索引,爲便於描述,我給加上惟一索引。

順便說明一下,「like」是關鍵字,我通常不建議使用關鍵字做爲庫名、表名、字段名或索引名。

我把他的疑問翻譯一下,在併發場景下,同時有兩我的,設置爲關注對方,就可能致使沒法成功加爲朋友關係。

如今,我用你已經熟悉的時刻順序表的形式,把這兩個事務的執行語句列出來:

圖 3 併發「喜歡」邏輯操做順序

因爲一開始 A 和 B 之間沒有關注關係,因此兩個事務裏面的 select 語句查出來的結果都是空。

所以,session 1 的邏輯就是「既然 B 沒有關注 A,那就只插入一個單向關注關係」。session 2 也一樣是這個邏輯。

這個結果對業務來講就是 bug 了。由於在業務設定裏面,這兩個邏輯都執行完成之後,是應該在 friend 表裏面插入一行記錄的。

如提問裏面說的,「第 1 步即便使用了排他鎖也不行,由於記錄不存在,行鎖沒法生效」。不過,我想到了另一個方法,來解決這個問題。

首先,要給「like」表增長一個字段,好比叫做 relation_ship,並設爲整型,取值 一、二、3。

值是 1 的時候,表示 user_id 關注 liker_id;
值是 2 的時候,表示 liker_id 關注 user_id;
值是 3 的時候,表示互相關注

而後,當 A 關注 B 的時候,邏輯改爲以下所示的樣子:

應用代碼裏面,比較 A 和 B 的大小,若是 A<B,就執行下面的邏輯

mysql> begin; /* 啓動事務 */
insert into `like`(user_id, liker_id, relation_ship) values(A, B, 1) on duplicate key update relation_ship=relation_ship | 1;
select relation_ship from `like` where user_id=A and liker_id=B;
/* 代碼中判斷返回的 relation_ship,
  若是是 1,事務結束,執行 commit
  若是是 3,則執行下面這兩個語句:
  */
insert ignore into friend(friend_1_id, friend_2_id) values(A,B);
commit;

若是 A>B,則執行下面的邏輯

mysql> begin; /* 啓動事務 */
insert into `like`(user_id, liker_id, relation_ship) values(B, A, 2) on duplicate key update relation_ship=relation_ship | 2;
select relation_ship from `like` where user_id=B and liker_id=A;
/* 代碼中判斷返回的 relation_ship,
  若是是 2,事務結束,執行 commit
  若是是 3,則執行下面這兩個語句:
*/
insert ignore into friend(friend_1_id, friend_2_id) values(B,A);
commit;

這個設計裏,讓「like」表裏的數據保證 user_id < liker_id,這樣不管是 A 關注 B,仍是B 關注 A,在操做「like」表的時候,若是反向的關係已經存在,就會出現行鎖衝突。

而後,insert … on duplicate 語句,確保了在事務內部,執行了這個 SQL 語句後,就強行佔住了這個行鎖,以後的 select 判斷 relation_ship 這個邏輯時就確保了是在行鎖保護下的讀操做。

操做符 「|」 是按位或,連同最後一句 insert 語句裏的 ignore,是爲了保證重複調用時的冪等性。

這樣,即便在雙方「同時」執行關注操做,最終數據庫裏的結果,也是 like 表裏面有一條關於 A 和 B 的記錄,並且 relation_ship 的值是 3, 而且 friend 表裏面也有了 A 和 B 的這條記錄。

不知道你會不會吐槽:以前明明還說盡可能不要使用惟一索引,結果這個例子一上來我就建立了兩個。這裏我要再和你說明一下,以前文章咱們討論的,是在「業務開發保證不會插入重複記錄」的狀況下,着重要解決性能問題的時候,才建議儘可能使用普通索引。

而像這個例子裏,按照這個設計,業務根本就是保證「我必定會插入重複數據,數據庫必定要要有惟一性約束」,這時就沒啥好說的了,惟一索引建起來吧。

4、小結

這是專欄的第一篇答疑文章。

我針對前 14 篇文章,你們在評論區中的留言,從中摘取了關於日誌和索引的相關問題,串成了今天這篇文章。這裏我也要再和你說一聲,有些我答應在答疑文章中進行擴展的話題,今天這篇文章沒來得及擴展,後續我會再找機會爲你解答。因此,篇幅所限,評論區見吧。

最後,雖然這篇是答疑文章,但課後問題仍是要有的。

咱們建立了一個簡單的表 t,並插入一行,而後對這一行作修改。

mysql> CREATE TABLE `t` (
`id` int(11) NOT NULL primary key auto_increment,
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB;
insert into t values(1,2);

這時候,表 t 裏有惟一的一行數據 (1,2)。假設,我如今要執行:

mysql> update t set a=2 where id=1;

你會看到這樣的結果:

結果顯示,匹配 (rows matched) 了一行,修改 (Changed) 了 0 行。

僅從現象上看,MySQL 內部在處理這個命令的時候,能夠有如下三種選擇:

1. 更新都是先讀後寫的,MySQL 讀出數據,發現 a 的值原本就是 2,不更新,直接返回,執行結束;
2. MySQL 調用了 InnoDB 引擎提供的「修改成 (1,2)」這個接口,可是引擎發現值與原來相同,不更新,直接返回;
3. InnoDB 認真執行了「把這個值修改爲 (1,2)"這個操做,該加鎖的加鎖,該更新的更新。

你以爲實際狀況會是以上哪一種呢?你能否用構造實驗的方式,來證實你的結論?進一步地,能夠思考一下,MySQL 爲何要選擇這種策略呢?

你能夠把你的驗證方法和思考寫在留言區裏,我會在下一篇文章的末尾和你討論這個問題。感謝你的收聽,也歡迎你把這篇文章分享給更多的朋友一塊兒閱讀。

5、上期問題時間

上期的問題是,用一個計數表記錄一個業務表的總行數,在往業務表插入數據的時候,須要給計數值加 1。

邏輯實現上是啓動一個事務,執行兩個語句:

1. insert into 數據表;
2. update 計數表,計數值加 1。

從系統併發能力的角度考慮,怎麼安排這兩個語句的順序。

這裏,我直接複製 @阿建 的回答過來供你參考:

併發系統性能的角度考慮,應該先插入操做記錄,再更新計數表。知識點在《行鎖功過:怎麼減小行鎖對性能的影響?》

由於更新計數表涉及到行鎖的競爭,先插入再更新能最大程度地減小事務之間的鎖等待,提高併發度。

評論區有同窗說,應該把 update 計數表放後面,由於這個計數表可能保存了多個業務表的計數值。若是把 update 計數表放到事務的第一個語句,多個業務表同時插入數據的話,等待時間會更長。

這個答案的結論是對的,可是理解不太正確。即便咱們用一個計數表記錄多個業務表的行數,也確定會給表名字段加惟一索引。相似於下面這樣的表結構:

在更新計數表的時候,必定會傳入 where table_name=$table_name,使用主鍵索引,更新加行鎖只會鎖在一行上。
而在不一樣業務表插入數據,是更新不一樣的行,不會有行鎖。

6、經典留言


一、某、人


孔乙己:孔乙己來到酒館大喊一聲老闆來二兩酒賒着,酒館生意太好,老闆把孔乙己的欠帳記錄記到小黑板上並記錄了孔乙己點的菜單。
孔乙己跟別人吹了會牛,忘了叫的幾兩酒了。又給老闆說,老闆把酒改爲二兩。
老闆也不肯定孔乙己叫沒叫酒,就去查菜單,發現孔乙己確實點了酒,可是原本就二兩,也就可貴麻煩了,又要修改小黑板,又要改菜單。
直接就給孔乙己說已經改好了


老闆看完板:正要告知孔乙己今日總帳是賒帳二兩酒,
小二連忙過來攔住:「老闆,剛剛孔乙己剛又賒帳了一碟茴香豆。」
老闆大驚:「差點虧了我一碟豆子!我怎不知?」
小二道:「老闆你方纔看板的之時沒拿記帳筆,我看記帳筆沒人使用,按店規天然可用。老闆你本身沒看」

老闆驚呼,「虧的你當心」。

暗地想店規確有不妥。

因而把店規「變帳須用記帳筆。」 改成
「改賬均須動筆。縱爲不變之賬,仍需覆寫之」

二、null


看到本身的問題上榜,這是對本身的最大鼓勵。

學習專欄以前,本身只是一個 CRUD boy,平時同事間討論 MySQL 的問題,本身徹底搭不上話,由於對 MySQL 底層原理徹底不懂。對 MySQL 的認知就僅限一點:索引能提升查詢效率。可是爲何能提升?不知道!!

如今回想,之前犯過不少錯誤:
1. 主鍵使用 UUID,非自增主鍵。
2. 濫用索引,其實能夠經過「最左前綴原則」來精減索引。
3. 無論 SQL 語句是否合理,只要能返回結果集就是好 SQL。
4. 建表時字段類型拿捏不許。

如今都會反覆學習專欄的每一篇文章,每次學習都有不同的收穫。
第一次多是:喔,原來有這麼個知識點,但對它的實現原理只知其一;不知其二。
第二次倒是:對它的實現原理有了更深的認識,增強對知識的理解,基本會造成一個比較清晰的邏輯。
第三次是,MySQL 的這種實現原理,是爲了解決什麼問題等等。

如今感受有點「走火入魔」了,之前執行查詢語句,關注的多久能返回結果集。


如今關注的倒是:鏈接器、分析器、優化器、執行器和 InnoDB 引擎。
鏈接成功後,獲取個人權限,查詢緩存,命中緩存直接返回,不然進行後續的操做。(記得老師留言區回覆過:鏈接器取權限,執行器用權限。而編寫留言到這產生了一個疑問:查詢緩存前,應該會校驗權限,因此鏈接器也會用權限?)
分析器階段進行詞法分析,解析關鍵字,字段名,表名等。語法分析判斷語法是否正確。(記得第一篇《基礎架構》留言提到語義分析,今晚要找資料學習下)。
優化器階段生成執行計劃,選擇索引(這時會懷疑 MySQL 選擇的索引是否最優),可否使用索引下推和覆蓋索引減小回表查詢,提升性能。
執行器階段調用引擎接口查詢數據,Server 層要啥,引擎給啥,InnoDB 只給必要的值。
查詢結束後,返回結果集,並將結果集放入查詢緩存。

更新語句的關注點是隔離性,視圖,MVCC,回滾日誌,redo log,binlog,兩階段提交等。
寫業務代碼時,會考慮事務內的 SQL 語句,可否調整 SQL 語句的順序,減小更新表時行鎖對性能的影響。
在建表的時,會反覆推敲這個索引是否合理。使用普通索引仍是惟一索引更爲合適。可否經過「最左前綴原則」來減小建立索引的個數。若是索引字段的類型是字符串並長度太長,如何優化使用前綴索引,減小空間佔用,提升查詢性能。

學習專欄後,基本上涉及到 MySQL 的內容,這些知識點都會浮如今腦海中。昨天還差點應用這些知識,幫同事優化他的 SQL 語句。昨天跟往常同樣,當寫代碼寫累了,就跑到同事那溜達溜達。
他正在線上的備庫測試查詢百萬數據要多久,另外一位同事建議他使用 force index 強制索引,此次執行 5 秒,再執行零點幾秒。
他驚乎,爲啥此次這麼快。我說,此次查了緩存。我還想幫他看看 SQL 語句,是否 MySQL 選擇錯了索引,致使使用 force index 顯式指定索引。說不定使用 order by field 就解決了呢,哈哈哈哈。後面有事,沒有繼續跟進他這問題了。

很是感恩,跟着老師學習,讓我體會到了學習是一件天然而又充滿魅力的事情,也讓我從一個基礎不牢固的小白,一步步地充實了本身的知識庫,另外老師很是盡責,常常半夜回覆答疑,但願老師保重身體。謝謝!!


做者回復: 「我說,此次查了緩存」

哈哈,這個場景好棒,這個畫面感,有一種掃地僧的感受👍🏿

一塊兒加油

三、螢火蟲


林老師的每次更新我都會跟着看 跟着學 已經堅持15節課了 受益良多 只是內心有時會反問本身 底層原理有那麼重要嗎? 會用不就好了嗎?
本身不知道該怎麼推翻這些想法 加上本身有個很差的習慣 就是容易放棄 但願本身可以堅持到最後。

 

做者回復: 加油。

說下我本身的理解。

我在帶新人的時候,要求你們在寫SQL語句的時候,內心是有數的,知道每一個語句執行的結果,以及這些代碼會消耗什麼資源、若是慢了會慢在哪裏、每一個語句執行會佔用哪些鎖等等。

有的新人會問「爲何須要這麼麻煩,我執行一下,看看結果對不對,對了就行,不對就改,是否是也能夠?」

我說不能夠。由於若是這樣,咱們就會受到不少侷限,即便咱們定位本身是業務開發人員。

這裏我說一個限制:

這會限制基於數據庫的業務架構能力。一個語句能夠試,一個五個語句的事務分析就要試不少次,一個複雜業務系統的數據庫設計,是試不出來的。

原理能夠幫咱們剪枝,排除掉那些理論上明顯錯誤的方案,這樣纔有精力真的去試那些有限的、可能正確的方案。


咱們不須要100%精通MySQL(我本身離這個目標也相去甚遠),可是隻要多知道一些原理,就能多剪一些枝,架構設計就能少一些錯誤選項的干擾,設計出來的項目架構正確的可能性更高。

我本身特別喜歡這個剪枝的過程和感受,他表示我用之前學習的時間,來節省了如今工做的時間。


固然,「原理」是一個很大的概念,有的原理更接近實戰,有的遠一些。這個專欄我挑的是跟平時使用相關的原理,以便你們能夠有機會邊學邊用。

一塊兒加油吧

相關文章
相關標籤/搜索