MYSQL 45 講 學習筆記

MYSQL 45講學習筆記

一、一條sql是怎麼執行的

  • mysql的架構:

    客戶端

    連接器

    查詢緩存

    分析器

    優化器

    執行器

    存儲引擎

二、一條SQL更新是如何執行的

重要的日誌模塊redolog、binlog

  • redolog

    這裏舉了一個孔乙己老闆賒賬記賬的故事。

    一條記錄需要更新的時候,innoDB引擎會先把記錄寫到redo日誌中,然後更新內存,這時候算是完成了,等到系統比較空閒的時候,才把redo日誌更新到磁盤中。

    relog的特點:只有在innodb中才有,是幾個文件,循環寫入(也就是如果滿了,那麼就把記錄更新一下,然後擦除,然後補上去)

  • binlog

    (1)binglog是Server層的日誌,其實也就是執行器記錄的日誌。

    (2)這裏先說一下更新一行記錄做的過程:重點🚨

    • 執行器找引擎要id=2的那一行記錄,拿到以後,給他+1,
    • 之後調用引擎的接口,引擎更新把這條 記錄更新到內存中,並記錄把這操作記錄到redolog中,redolog處於prepare狀態,告訴執行器我執行完了,隨時可以提交事務。
    • 執行器生成這個操作的binlog日誌,然後調用引擎的提交事務接口,引擎也把redolog改爲提交commit狀態,更新完成。

    (3)根據log的寫入順序我們可以知道1個事情:

    • 如果沒有redolog,在引擎執行命令的時候發生異常,是沒法恢復的,因爲binlog還沒有記 錄擦操作。cash-save

    (4)那麼爲什麼redolog有兩個狀態?

    • 結合兩個日誌的寫入順序,假設在引擎處redolog已經寫了,然後系統掛掉了,那麼binglog還沒記錄,這個時候如果系統重啓時會讀redolog的東西的,但是你binlog你沒有這個記錄呀,當你加入要創建一個從庫,使用binlog創建,就會少一條操作記錄,主從數據庫內容就不一樣了。
    • 上面一點講到的從庫,備庫是經常做的事情,他們一般使用全量備份+binlog歸檔來實現,這個時候binglog如果少了一條操作記錄,主從就會不一致的。

    (5)說一說爲什麼DBA能夠將數據庫恢復到任何時間

    • 其實就是第一個有一個備份庫,第二個就是依靠binlog

三、隔離問題

讀未提交 讀已提交 可重複度 串行化(表鎖

那麼其實本質上是數據庫創建了個視圖,這樣就能做到可重複度和讀已提交

在MYSQL中實際上,每條記錄在更新的時候都會記錄一條回滾操作。因此也會存在一個問題,這記錄回滾操作一定不能太多,當你是一個長事務的時候就會讓這些回滾記錄非常大,要避免這種情況,其實就是當你開啓事務的時候,最後一定要提交或者回滾。重點🚨

四、深入淺出索引(一)

  • 分爲主鍵索引和普通索引,在innodb中,表都是根據主鍵順序存放的。假設一個表中有主鍵,有普通索引,如果用普通索引去查數據,實際過程中,他是先用普通索引找到對應的主鍵,然後根據主鍵的索引去找到應對的記錄。其實原因就是主鍵索引存放的是整行數據,普通索引存放的是對應主鍵的信息。這個過程也叫做重點:回表。**因此爲了提高效率,我們應該用主鍵來查詢數據。**也正是因爲有回表,所以innodb一定要有主鍵,這是他的B+樹結構決定的,而MYisam就不需要了,也是因爲他的B+樹存的是地址導致的,這個後面我們會講到。🚨
  • 看了上面,我們知道普通索引存的其實是主鍵信息,那麼其實在某種情況下,主鍵的確定也很重要,比如一個表要記錄身份證,你會把身份中作爲主鍵嗎?應該不可以的,這樣普通索引每個佔用的空間就很大,應該使用一般的數字自增就行了。
  • mysql的innodb使用B+樹,其實也就是N叉樹,爲什麼呢?其實就是二叉樹的存放數據太分散了,太分散的數據尋址一定是耗時的,使用N叉樹就能避免多次的分區尋址
  • B+樹的頁分裂。頁分裂就是你的新id在索引二叉樹中超過了N,這個時候就要分裂,經常的分裂會的導致效率貶低,所以建議使用自增長的主鍵作爲索引,反例就是身份證做主鍵,每次添加的身份證id太隨機了,就經常需要頁分裂。在使用InnoDB存儲引擎時,如果沒有特別的需要,請永遠使用一個與業務無關的自增字段作爲主鍵。
  • 頁合併:如果刪除了某個索引的一些值,如果不處理的話,我們要經過的節點會多一點,如果把二叉樹重新整頓一下的話,經過的會更少。一般我們會設置,如果節點的數量小於N/2 就和附近的節點合併一下。

五、深入淺出索引(二)

  • 覆蓋索引:我們知道了有回表這一現象的存在,本質是普通索引存的是主鍵信息,如果我們要的東西就是主鍵呢?,這樣就不用回表了,這樣就提高速度了。

  • 最左前綴原則,假如我有了a,b兩者的聯合主鍵,請問我是否要單獨創建一個a的主鍵呢?答案是不用,因爲B+樹的索引機構,可以利用他的最左前綴來定位。比如你要找到張三的信息,(老王,1),(老豆,2)(張三,10),(張三,20),根據聯合主鍵他會迅速找到(張三,10),然後依次向後找符合張三條件的。**就是隻要滿足最左前綴,那麼就可以使用索引,重要🚨。**所以我們在創建聯合索引的時候,前後順序要考慮一下,原則就是可以少維護一個索引,就是不錯的。

  • 索引下推:比如我們要搜索姓氏是張,年齡爲10的男孩,索引是姓名和年齡的聯合索引。在mysql5.6之前它會先找到張開頭的,然後回表,去對比年齡爲10的,5.6以後,能夠做到,找到張開頭以後,直接對比年齡是否符合要求,然後再回表獲取其他信息。這樣極大減少了回表次數。

  • 我們再仔細研究一下索引的使用情況:也就是在有聯合索引的時候,不同語句情況下,到底所有有生效嗎?基本基於最左前綴原則

    我們假設有個表:employees.titles表,他的聯合主鍵索引是<emp_no, title, from_date> 我們分別看一下不同sql使用索引的情況:

    • select * from employees.titles where emp_no=‘1’ and titile=‘1’ and from_date=‘2020’;
      • 這個是全列匹配,聯合索引的字段都用上了
    • select * from employees.titles where emp_no=‘1’
      • 最左前綴匹配,這樣用到了emp_no一個索引
    • SELECT * FROM employees.titles WHERE emp_no=‘10001’ AND from_date=‘1986-06-26’;
      • 這裏和上面一樣,他缺失了title這個字段,最後只用到了emp_no一個索引。
    • SELECT * FROM employees.titles WHERE from_date=‘1986-06-26’;
      • 這中就不會用到索引 — 索引失效🚨
    • SELECT * FROM employees.titles WHERE emp_no=‘10001’ AND title LIKE ‘Senior%’;
      • 這個會用到索引,但是有要求,%不能在開頭,否則失效,只用到一個索引。
    • SELECT * FROM employees.titles WHERE emp_no < ‘10010’ and title=‘Senior Engineer’;
      • 只有第一列的範圍才能用到索引,而且只是第一個索引,後面的title都不會走走索引。
    • SELECT * FROM employees.titles WHERE emp_no=‘10001’ AND left(title, 6)=‘Senior’;
      • 對於有函數的是不會用索引的,也就是這一句只用到了emp_no這個索引。

六、B樹、B+樹的知識

這個博客講的特別好:http://blog.codinglabs.org/articles/theory-of-mysql-index.html 2011年的,太厲害了,主要的圖片也是來自於這篇博客,總之寫得很精彩。

  • 索引是磁盤上的東西,一般來說很大(我們講那種索引大的情況),讀索引的過程是把索引文件讀到內存中,對於索引很大的文件,就會需要分部分來讀取。

  • 對於平衡二叉樹或者是紅黑樹,物理實現上是數組,相關聯的數據有時候是距離很遠的,這就會導致你讀的索引部分會很多,這樣效率會很低的。

  • 爲了索引而出現的結構就是B樹了。

  • 有個概念叫做局部性原理,就是磁盤預讀,讀取磁盤的時候,會把這個地址後面的東西也讀取到內存中,所以我們應該把相近的數據放到一起,這樣能夠一起讀取出來,減少io次數。這個原理是屬於計算機原理的知識。

  • 那麼對於B樹,我們知道他是N叉書,也就是一個節點存了N個數據,這樣就能充分利用這個局部性原理和磁盤預讀。

  • B樹的結構圖:他的特點是:

    • 每個非葉子節點(非?)由key和指針組成,key數量是指針數量+1。
    • key從左到右升序
    • 如圖我們可以看到比15大,比56小的,依靠他們中間的指針指向下一個節點,這個節點的key一定是小於56,大於15
      在這裏插入圖片描述
    // 他的搜索僞代碼
    BTree_Search(node, key) {
        if(node == null) return null;
        foreach(node.key)
        {
            if(node.key[i] == key) return node.data[i];
                if(node.key[i] > key) return BTree_Search(point[i]->node);
        }
        return BTree_Search(point[i+1]->node);
    }
    data = BTree_Search(root, my_key);
    
  • B+樹的結構是:一些特點:

    • 他的內節點不存data數據,只有key
    • 他的葉子節點沒有指針

在這裏插入圖片描述

  • B+樹真正使用會進一步改進,如下圖:改進點:

    • 帶有順序訪問指針,提高了區間訪問能力,當我們查詢15到30的數的時候,定位到15以後,直接完後找就完事了。這也是爲什麼說B樹找範圍能力沒有B+樹厲害

在這裏插入圖片描述
總結一下:兩個問題:

  1. 平衡二叉樹/紅黑樹 與 B樹的區別是什麼?爲什麼索引要用B樹而不用那兩個呢?
  • 平衡二叉樹是二叉樹,每個節點只有兩個葉子節點,關聯的數據可能在不同的位置,讀取次數多,效率低下。
  • B樹就是爲了解決這問題而誕生的,他的多叉樹特性保證了他讀取io的次數會降低,而卻他的節點數據是有順序的,利用了磁盤預讀的特點。
  1. B樹和B+樹的區別
    • B+樹葉子節點不存放指針,只存放着數據,這樣只需要遍歷葉子節點以及下一個葉子節點即可。
    • B+樹的結構是有序數組鏈表+平衡多叉樹,B樹是有序數組+平衡多叉樹。也就是B+樹的葉子節點是個鏈表,每個數據指向下一個相鄰的數據。
    • B+樹的特點決定了他很擅長範圍查找,而b樹沒法和他比較。
  • MyISAM和innoDB的索引結構區別

    • myisam索引最後一個葉子節點存放的是地址,普通索引和主鍵索引是一樣的,也是存放地址,地址指向對應的數據庫記錄。也叫做非聚集索引,索引和數據是分離的
      在這裏插入圖片描述

    • innoDB

      對於主鍵,他存的不是地址,而是整個記錄,就是innoDB的數據文件本身就是索引文件,myisam的索引和數據是分離的。普通索引的節點存的內容是主鍵。
      在這裏插入圖片描述

  • InnoDB和MyISAM分別是怎麼存儲數據的,優缺點是什麼— 後面總結一下,不單是結構問題,還有事務,鎖等問題考慮對比。

    MyIsam不支持事務。

七、全局鎖和表鎖

鎖分爲全局鎖、表鎖、行鎖

  • 全局鎖:

    鎖住全表,只能進行select查詢操作,增刪改,ddl都不行,一般用於我們需要備份主庫的時候。語法是Flush table with read lock,開啓時候就會鎖住全部的表,但是如果有用戶在我們備份的時候操作怎麼辦了?只能等我們結束嗎?其實不然,結合之前我們講隔離級別的時候,我們有提到數據庫會有回滾記錄,或者說是MVCC版本控制,他給你一個視圖,你可以對視圖操作,實際操作上就是你在鎖住全表之前,開啓一個事務,就行了,官方自帶的邏輯備份工具mysqldump。當 mysqldump 使用參數–single-transaction 的時候,導數據之前就會啓動一個事務。

  • 表鎖:

    表鎖分爲兩種:表鎖,元數據鎖MDL

    • 表鎖:語法是lock tables … read/write,來鎖中某個表。假設我們有兩個會話AB,如果會話A 執行lock t1 read,那麼會話A就只能查詢t1表,查詢其他表會報read lock沒有釋放的錯誤。而會話B能查t1表,也可以查其他表,但是insert這個表會一直被阻塞,直到會話A執行unlock tables。

      也就是在某個會話中lock 了一些表特定的read或者write,那麼首先他無法訪問其他表了,其次對於他lock的那些表只能進行lock的操作。🚨

      明顯這種限制太大了,Myisam還會用這樣的方式,但是innoDB有顆粒度更細緻的行鎖,幾乎是不會使用表鎖的。

    • 元數據鎖metadata lock:是表層面的鎖

      這個是數據庫自動給我們加的鎖,當你有增刪改查的時候自動加上讀鎖。當你有DDL語句的時候,就會自動加上寫鎖。寫鎖之間是互斥的,兩個DDL寫的操作要按照順序執行。讀寫鎖之間也是互斥的,另外加上MDL不會主動釋放鎖,只有在事務結束以後纔會釋放鎖,當我們給一個表加字段的時候,就容易導致數據庫掛掉。

      解決辦法就是,先去看看select * from information_schema.innodb_trx;這表裏面的事務,考慮把它停掉,或者是我們的DDL語句設置等待時間。

    這一部分呢,1、只要就是要知道MDL鎖對我們新增一個字段的影響,已經我們該怎麼做去避免影響。2、就是全局鎖主要應用在備份中,一般我們開啓事務後,在進行備份比較合適。🚨

八、行鎖的功過

行鎖就是鎖住每一行記錄的,是在存儲引擎中實現,比如MyISAM就沒有行鎖,只能用表鎖,也就是這個表同 一時刻只能有一個更新操作。這也是他被取代的原因。

  • 一個事務掌握一個行鎖之後,其他事務要對這行記錄操作,會被阻塞,只能等待那個行鎖釋放。

  • 在 InnoDB 事務中,行鎖是在需要的時候才加上的,但並不是不需要了就立刻釋放,而是要等到事務結束時才釋放。這個就是兩階段鎖協議。知道了這個設定,對我們使用事務有什麼幫助呢?那就是,如果你的事務中需要鎖多個行,要把最可能造成鎖衝突、最可能影響併發度的鎖儘量往後放。

    假設你負責實現一個電影票在線交易業務,顧客 A 要在影院 B 購買電影票。我們簡化一點,這
    個業務需要涉及到以下操作:

    1. 從顧客 A 賬戶餘額中扣除電影票價;

    2. 給影院 B 的賬戶餘額增加這張電影票價;

    3. 記錄一條交易日誌。

    也就是說,要完成這個交易,我們需要 update 兩條記錄,並 insert 一條記錄。當然,爲了保
    證交易的原子性,我們要把這三個操作放在一個事務中。那麼,你會怎樣安排這三個語句在事務
    中的順序呢?
    試想如果同時有另外一個顧客 C 要在影院 B 買票,那麼這兩個事務衝突的部分就是語句 2 了。
    因爲它們要更新同一個影院賬戶的餘額,需要修改同一行數據。
    根據兩階段鎖協議,不論你怎樣安排語句順序,所有的操作需要的行鎖都是在事務提交的時候才
    釋放的。所以,如果你把語句 2 安排在最後,比如按照 3、1、2 這樣的順序,那麼影院賬戶餘
    額這一行的鎖時間就最少。這就最大程度地減少了事務之間的鎖等待,提升了併發度。

  • 死鎖問題

    innodb是會自動檢測死鎖的,也就是如果發生了鎖等待,引擎會掃一遍所有鎖,看看是不是因爲自己的加入而導致的死鎖,如果是就會回滾事務,這樣別人就能走下去了。

    但是每次掃描太費CPU了,解決方向是減少併發度,可以在中間件裏控制範圍數據庫的併發量,或者是mysql修改源碼設置等待隊列。

總結一下鎖:🚨

  1. 全局鎖用於數據庫的備份,建議開始事務以後鎖庫然後備份,業務會友好點。
  2. 表鎖主要是MYISAM在用,lock xx read / write,就只能對這個表進行相應操作。幾乎沒啥意義。
  3. 表鎖的MDL是表層面的,所以寫指的是DDL,讀指的是增刪改查。讀寫鎖之間互斥,寫鎖之間也互斥。MDL在事務提交後釋放鎖。
  4. 行鎖也是事務提交以後纔會釋放,讀操作不會有互斥,更新操作就會有互斥情況。

九、事務到底是隔離的還是不隔離的

首先清楚innodb默認是可重複度PR,我們知道這可能會導致幻讀。下面我們探討的就是這麼做到的可重複度和讀已提交。

前面我們說到了每行數據的多版本控制,MVCC,本質是創建了一個視圖,這個視圖不是數據庫的那個視圖,其實是一個快照,或者說是一個up_limit_id,它的意義是:表示我只讀取比這個up_limit_id小於或者等於的數據版本。

那麼up_limit_id這是個什麼東西呢?是個版本號,每一次的事務操作都會生成一個row trx_id,那麼每次事務啓動的時候會獲取最大的那個row trx_id,也就是up_limit_id

還有一種情況會再一次獲取up_limit_id版本,就是更新操作,更新操作的執行順序是:先讀取,再更新。(因此我們看pdf裏面的Q1的最後結果是3。注意了他的事務C是自動提交的,但是AB都是begin,最後才提交,還有就是你測試的時候,要開多個窗口,纔是模擬多個事務)這個比較重要,再寫一遍:更新操作的執行順序是:先讀取,再更新。🚨

所以你能知道爲什麼他可以重複讀了吧。開啓事務記錄up_limit_id------>update就重新獲取一次,select就還是原來的id--------->獲取正確的版本 。 在可重複讀隔離級別下,只需要在事務開始的時候找到那個 up_limit_id,之後事務裏的其他查詢都共用這個 up_limit_id;

讀已提交隔離級別的時候就是:每一次的查詢都會更新一下 up_limit_id。

重點再說一遍:更新操作的執行順序是:先讀取,再更新🚨

所以你能知道爲什麼他可以重複讀了吧。開啓事務記錄up_limit_id------>update就重新獲取一次,select就還是原來的id--------->獲取正確的版本 。 在可重複讀隔離級別下,只需要在事務開始的時候找到那個 up_limit_id,之後事務裏的其他查詢都共用這個 up_limit_id;

讀已提交隔離級別的時候就是:每一次的查詢都會更新一下 up_limit_id。

十、MYSQL是怎麼保證主備一致的呢?

假設A是主庫,B是備庫。AB之間會有一個連接的,A內部有個專門的線程專門來通訊備庫。A庫接受到B庫從緩過來的位置,從本地讀取binlog,發給B,B拿到以後寫道自己本地叫做relay log,B中有專門的線程讀取中轉日誌,來執行。

實際情況AB兩個庫會設置成互爲主庫或者互爲輔庫。但B拿到A的binlog後執行,也會記錄binglog,A又拿到B的binlog,這不就循環複製了嗎?那麼binglog裏面有一個server_id,他會看是不是自己這臺機生成的binlog,如果是,那麼就不會執行。

十一、MYSQL怎麼保證高可用

  • 上面我們說的是一致性,這裏講的高可用值的是,主從之間的延遲情況。

  • 延遲指的是同一個事務,在A庫的執行完成的時間和在B庫執行完成的時間的差值。那麼真正耗時的不是binlog的傳遞,而是B庫讀取relaylog執行的快慢。可能導致這個速度的原因有:

    • 有些人會因爲備庫很少用,而把備庫的機器性能配置的很低。當然現在這種情況很少了,因爲主備之間經常切換。
    • 備庫壓力太大了。因爲有些人很故意生產的數據庫,所以儘可能的優先使用備庫去查數據,反而導致備庫壓力很大。解決辦法:
      • 一主多從
      • 把binlog給外部系統,比如hadoop,讓他們來做查詢的工作
    • 大事務。比如一次刪除很多數據
    • 輔庫的並行能力
  • 那麼MYSQL主備切換是個什麼過程呢?

    • 確認B庫的延時時間是否低於規定(防止高延遲,否則後面同步的時候很慢)
    • 把A庫改爲readonly
    • 同步A庫剩下的binlog,直到B庫的延遲時間爲0.
    • 把B庫改爲可讀寫
    • 把業務請求切換到B庫來

    這個叫做可靠性優先策略

十二、爲什麼備庫延遲幾個小時

對於主庫壓力,使用頻率非常高的情況,從庫如果延遲了,也許再也追不上主庫了。下面我們學習從庫的並行複製能力。

其實是什麼呢?就是從庫的讀取relay log是單線程的,併發度不夠,在MYSQL5.6以後就改爲多線程讀取了。

十三、主庫出現問題了,從庫怎麼辦

首先看一下一主多從的結構圖:主庫主要做寫操作以及一般小部分讀操作。從庫主要分到讀的操作。AA`互爲主備。

在這裏插入圖片描述

當主庫A掛掉以後,BCD會指向A`,他會成爲寫庫。
在這裏插入圖片描述

那麼有個問題,但A掛掉了,B去連接A`,但是不能保證A 和 A\在那個時刻是一樣的呀?當然你可以等到A主從庫之間完成同步,但是也可以打開GTID這個東西,在這個模式下一主多從切換就會方便很多。

十四、主從讀寫分離

一主多從架構的應用場景:讀寫分離。

讀寫分離在哪實現分開查詢不同數據庫。可能是在客戶端直連,也就是目前我這個項目的情況,直接選擇特定的數據源。第二個就是在客戶端和數據庫之間搞個代理,代理根據上下文來判斷應該去那個數據庫。

但是都會導致一個問題,如果我剛剛更新的主庫數據,我馬上要讀取,這個時候從庫還沒有同步呢,怎麼辦?這個問題不想主備庫之間延遲問題可以避免。這個不能100%避免。有以下幾種辦法:

  • 強制走主庫:區分我們的查詢,如果對於比如我買完東西,返回以後我一定要看到我的訂單,那麼就強制他到主庫去查。對於比如上新一個產品,晚一點看到也沒關係,那麼就放在從庫去查。看起來這個辦法是逃避現實的辦法,但是實際用的比較多。但是如果你的需求都是要求實時性的話,這個辦法就不太好了,因爲相當於沒有從庫了。
  • sleep方案,就是我在從庫查詢的時候,select sleep(1) 一下,這樣很大概率主從完成了同步,但是明顯者不太精確,可能本來只要0.5s的同步,硬生生被你拖到了1s。
  • 判斷主從是否無延遲。直接看延遲時間是否爲0,或者是GTID主從庫日誌的記錄
  • 更多的不做展開學習…

這幾種方案中,有的方案看上去是做了妥協,有的方案看上去不那麼靠譜兒,但都是有實際應用場景的,你需要根據業務需求選擇。

即使是最後等待位點和等待 GTID 這兩個方案,雖然看上去比較靠譜兒,但仍然存在需要權衡的情況。如果所有的從庫都延遲,那麼請求就會全部落到主庫上,這時候會不會由於壓力突然增大,把主庫打掛了呢?

其實,在實際應用中,這幾個方案是可以混合使用的。比如,先在客戶端對請求做分類,區分哪些請求可以接受過期讀,而哪些請求完全不能接受過期讀;然後,對於不能接受過期讀的語句,再使用等 GTID 或等位點的方案。

總結一下:

上面我們討論了

  • 主備/從之間是怎麼保持一致的,binlog,連接,relaylog,循環複製。
  • 怎麼實現高可用,就是主從之間的延遲情況。一主多從,主從對稱配置,輔庫少一點大事務,輔庫並行複製。
  • 主庫怎麼切換到備庫的,延遲時間限制----->主庫改爲只讀----->延遲時間爲0----->備庫改爲寫。
  • 一主多從模式下,主庫掛了,從機怎麼連接到備機。GTID 全局事務id。具體沒深入研究。
  • 讀寫分離導致的“過期讀”解決辦法。

十五、到底能不能用join

select * from t1 straight_join t2 on t1.a = t2.a;這個過程是這樣的:

  • 對驅動表t1拿取一行記錄。全部搞下來就是全表掃描
  • 每一行記錄獲取a,然後跟據a去t2表中查,這個查詢是樹搜索。
  • 找到t2中符合條件的行,和T1取出的數據組成一行
  • 循環第二第三步,直到走到t1表末尾

明顯的驅動表走全表掃描,被驅動表是走的樹查找,所有儘可能的驅動表要小一點(更仔細的說是,用各自的條件去看涉及的數據量多還是少)。前提是能夠使用到被驅動表的索引。

十六、MYISAM和InnoDB

My:沒有行鎖,沒有MMVC多版本控制,查詢會相對快一點

innoDB:有行鎖,索引是記錄有一定的緩存,有MVCC。

十七、索引失效的情況

  • or 讓本來有索引的反而不走索引了,除非你每個條件都有索引
  • 聯合索引如果不是第一個就不會使用到
  • 立刻以%開頭的,不會用到索引 N%表示N開頭,這個會用到索引
  • 如果列是字符串的,條件中一定要用引號標註
  • 如果mysql優化器判斷全表查找比用索引更加快,那麼就用全表查找
  • <> \ not \ in \ exists \
  • 語句包含函數

十八、幻讀學習

什麼是幻讀:第一次讀取數據庫,根據返回的結果後面的insert語句是沒有問題的,但是執行insert以後報錯主鍵衝突,這就是幻讀。

解決辦法:在一開始select的時候就加上一把行鎖。而serialize這個級別就是自動查詢的時候自動加行鎖,他也是唯一的不會幻讀的隔離級別。

這個深入學習要看一下原文了,next-key lock,間隙鎖+行鎖配合可以解決幻讀問題。

十九、鎖的分類

  • 樂觀鎖:首先先查出數據(連帶着版本),然後進行update的時候再查一次,如果這個時候的version和一開始的version一樣,那麼就update;java代碼應該是一個自旋。
  update table set a='a',version = version + 1 where version = #{version} and id = #{id}
  • 悲觀鎖:
    • 共享鎖:讀鎖。A事務lock in share mode 鎖住結果的每一行,A事務可以更新,但是其他事務不能再加讀鎖,更不能更新。其他會話可以讀取。也就是我讀取數據的時候,別的事務不允許改變數據。
    • 排他鎖:寫鎖,for update 一個會話中使用這個這個語句,那麼其他會話只能查不能改,只有前面那個會話可以改。目的就是我更新的時候別的會話別動。
    • 對於insertupdatedelete等操作。會自動給涉及的數據加排他鎖;

歡迎大家關注我新建的微信公衆號,我會持續分享和更新技術文章!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章