1. 程式人生 > >Mysql高手系列 - 第22篇:深入理解mysql索引原理,連載中

Mysql高手系列 - 第22篇:深入理解mysql索引原理,連載中

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。

歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。

這是Mysql系列第22篇。

背景

使用mysql最多的就是查詢,我們迫切的希望mysql能查詢的更快一些,我們經常用到的查詢有:

  1. 按照id查詢唯一一條記錄
  2. 按照某些個欄位查詢對應的記錄
  3. 查詢某個範圍的所有記錄(between and)
  4. 對查詢出來的結果排序

mysql的索引的目的是使上面的各種查詢能夠更快。

預備知識

什麼是索引?

上一篇中有詳細的介紹,可以過去看一下:什麼是索引?

索引的本質:通過不斷地縮小想要獲取資料的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,我們可以總是用同一種查詢方式來鎖定資料。

磁碟中資料的存取

以機械硬碟來說,先了解幾個概念。

扇區:磁碟儲存的最小單位,扇區一般大小為512Byte。

磁碟塊:檔案系統與磁碟互動的的最小單位(計算機系統讀寫磁碟的最小單位),一個磁碟塊由連續幾個($2^n$)扇區組成,塊一般大小一般為4KB。

磁碟讀取資料:磁碟讀取資料靠的是機械運動,每次讀取資料花費的時間可以分為尋道時間、旋轉延遲、傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁軌所需要的時間,主流磁碟一般在5ms以下;旋轉延遲就是我們經常聽說的磁碟轉速,比如一個磁碟7200轉,表示每分鐘能轉7200次,也就是說1秒鐘能轉120次,旋轉延遲就是1/120/2 = 4.17ms;傳輸時間指的是從磁碟讀出或將資料寫入磁碟的時間,一般在零點幾毫秒,相對於前兩個時間可以忽略不計。那麼訪問一次磁碟的時間,即一次磁碟IO的時間約等於5+4.17 = 9ms左右,聽起來還挺不錯的,但要知道一臺500 -MIPS的機器每秒可以執行5億條指令,因為指令依靠的是電的性質,換句話說執行一次IO的時間可以執行40萬條指令,資料庫動輒十萬百萬乃至千萬級資料,每次9毫秒的時間,顯然是個災難。

mysql中的頁

mysql中和磁碟互動的最小單位稱為頁,頁是mysql內部定義的一種資料結構,預設為16kb,相當於4個磁碟塊,也就是說mysql每次從磁碟中讀取一次資料是16KB,要麼不讀取,要讀取就是16KB,此值可以修改的。

資料檢索過程

我們對資料儲存方式不做任何優化,直接將資料庫中表的記錄儲存在磁碟中,假如某個表只有一個欄位,為int型別,int佔用4個byte,每個磁碟塊可以儲存1000條記錄,100萬的記錄需要1000個磁碟塊,如果我們需要從這100萬記錄中檢索所需要的記錄,需要讀取1000個磁碟塊的資料(需要1000次io),每次io需要9ms,那麼1000次需要9000ms=9s,100條資料隨便一個查詢就是9秒,這種情況我們是無法接受的,顯然是不行的。

我們迫切的需求是什麼?

我們迫切需要這樣的資料結構和演算法:

  1. 需要一種資料儲存結構:當從磁碟中檢索資料的時候能,夠減少磁碟的io次數,最好能夠降低到一個穩定的常量值
  2. 需要一種檢索演算法:當從磁碟中讀取磁碟塊的資料之後,這些塊中可能包含多條記錄,這些記錄被載入到記憶體中,那麼需要一種演算法能夠快速從記憶體多條記錄中快速檢索出目標資料

我們來找找,看是否能夠找到這樣的演算法和資料結構。

我們看一下常見的檢索演算法和資料結構。

迴圈遍歷查詢

從一組無序的資料中查詢目標資料,常見的方法是遍歷查詢,n條資料,時間複雜度為O(n),最快需要1次,最壞的情況需要n次,查詢效率不穩定。

二分法查詢

二分法查詢也稱為折半查詢,用於在一個有序陣列中快速定義某一個需要查詢的資料。

原理是:

先將一組無序的資料排序(升序或者降序)之後放在陣列中,此處用升序來舉例說明:用陣列中間位置的資料A和需要查詢的資料F對比,如果A=F,則結束查詢;如果A<F,則將查詢的範圍縮小至陣列中A資料右邊的部分;如果A>F,則將查詢範圍縮小至陣列中A資料左邊的部分,繼續按照上面的方法直到找到F為止。

示例:

從下列有序數字中查詢數字9,過程如下

[1,2,3,4,5,6,7,8,9]

第1次查詢:[1,2,3,4,5,6,7,8,9]中間位置值為5,9>5,將查詢範圍縮小至5右邊的部分:[6、7、8、9]

第2次查詢:[6、7、8、9]中間值為8,9>8 ,將範圍縮小至8右邊部分:[9]

第3次查詢:在[9]中查詢9,找到了。

可以看到查詢速度是相當快的,每次查詢都會使範圍減半,如果我們採用順序查詢,上面資料最快需要1次,最多需要9次,而二分法查詢最多隻需要3次,耗時時間也比較穩定。

二分法查詢時間複雜度是:O(logN)(N為資料量),100萬資料查詢最多隻需要20次($2^{20}$=1048576‬)

二分法查詢資料的優點:定位資料非常快,前提是:目標陣列是有序的。

有序陣列

如果我們將mysql中表的資料以有序陣列的方式儲存在磁碟中,那麼我們定位資料步驟是:

  1. 取出目標表的所有資料,存放在一個有序陣列中
  2. 如果目標表的資料量非常大,從磁碟中載入到記憶體中需要的記憶體也非常大

步驟取出所有資料耗費的io次數太多,步驟2耗費的記憶體空間太大,還有新增資料的時候,為了保證陣列有序,插入資料會涉及到陣列內部資料的移動,也是比較耗時的,顯然用這種方式儲存資料是不可取的。

連結串列

連結串列相當於在每個節點上增加一些指標,可以和前面或者後面的節點連線起來,就像一列火車一樣,每節車廂相當於一個節點,車廂內部可以儲存資料,每個車廂和下一節車廂相連。

連結串列分為單鏈表和雙向連結串列。

單鏈表

每個節點中有持有指向下一個節點的指標,只能按照一個方向遍歷連結串列,結構如下:

//單項鍊表
class Node1{
    private Object data;//儲存資料
    private Node1 nextNode;//指向下一個節點
}

雙向連結串列

每個節點中兩個指標,分別指向當前節點的上一個節點和下一個節點,結構如下:

//雙向連結串列
class Node2{
    private Object data;//儲存資料
    private Node1 prevNode;//指向上一個節點
    private Node1 nextNode;//指向下一個節點
}

連結串列的優點:

  1. 可以快速定位到上一個或者下一個節點
  2. 可以快速刪除資料,只需改變指標的指向即可,這點比陣列好

連結串列的缺點:

  1. 無法向陣列那樣,通過下標隨機訪問資料
  2. 查詢資料需從第一個節點開始遍歷,不利於資料的查詢,查詢時間和無需資料類似,需要全遍歷,最差時間是O(N)

二叉查詢樹

二叉樹是每個結點最多有兩個子樹的樹結構,通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹常被用於實現二叉查詢樹和二叉堆。二叉樹有如下特性:

1、每個結點都包含一個元素以及n個子樹,這裡0≤n≤2。
2、左子樹和右子樹是有順序的,次序不能任意顛倒,左子樹的值要小於父結點,右子樹的值要大於父結點。

陣列[20,10,5,15,30,25,35]使用二叉查詢樹儲存如下:

每個節點上面有兩個指標(left,rigth),可以通過這2個指標快速訪問左右子節點,檢索任何一個數據最多隻需要訪問3個節點,相當於訪問了3次資料,時間為O(logN),和二分法查詢效率一樣,查詢資料還是比較快的。

但是如果我們插入資料是有序的,如[5,10,15,20,30,25,35],那麼結構就變成下面這樣:

二叉樹退化為了一個連結串列結構,查詢資料最差就變為了O(N)。

二叉樹的優缺點:

  1. 查詢資料的效率不穩定,若樹左右比較平衡的時,最差情況為O(logN),如果插入資料是有序的,退化為了連結串列,查詢時間變成了O(N)
  2. 資料量大的情況下,會導致樹的高度變高,如果每個節點對應磁碟的一個塊來儲存一條資料,需io次數大幅增加,顯然用此結構來儲存資料是不可取的

平衡二叉樹(AVL樹)

平衡二叉樹是一種特殊的二叉樹,所以他也滿足前面說到的二叉查詢樹的兩個特性,同時還有一個特性:

它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。

平衡二叉樹相對於二叉樹來說,樹的左右比較平衡,不會出現二叉樹那樣退化成連結串列的情況,不管怎麼插入資料,最終通過一些調整,都能夠保證樹左右高度相差不大於1。

這樣可以讓查詢速度比較穩定,查詢中遍歷節點控制在O(logN)範圍內

如果資料都儲存在記憶體中,採用AVL樹來儲存,還是可以的,查詢效率非常高。不過我們的資料是存在磁碟中,用過採用這種結構,每個節點對應一個磁碟塊,資料量大的時候,也會和二叉樹一樣,會導致樹的高度變高,增加了io次數,顯然用這種結構儲存資料也是不可取的。

B-樹

B槓樹,千萬不要讀作B減樹了,B-樹在是平衡二叉樹上進化來的,前面介紹的幾種樹,每個節點上面只有一個元素,而B-樹節點中可以放多個元素,主要是為了降低樹的高度。

一棵m階的B-Tree有如下特性【特徵描述的有點繞,看不懂的可以跳過,看後面的圖】:

  1. 每個節點最多有m個孩子,m稱為b樹的階
  2. 除了根節點和葉子節點外,其它每個節點至少有Ceil(m/2)個孩子
  3. 若根節點不是葉子節點,則至少有2個孩子
  4. 所有葉子節點都在同一層,且不包含其它關鍵字資訊
  5. 每個非終端節點包含n個關鍵字(健值)資訊
  6. 關鍵字的個數n滿足:ceil(m/2)-1 <= n <= m-1
  7. ki(i=1,…n)為關鍵字,且關鍵字升序排序
  8. Pi(i=1,…n)為指向子樹根節點的指標。P(i-1)指向的子樹的所有節點關鍵字均小於ki,但都大於k(i-1)

B-Tree結構的資料可以讓系統高效的找到資料所在的磁碟塊。為了描述B-Tree,首先定義一條記錄為一個二元組[key, data] ,key為記錄的鍵值,對應表中的主鍵值,data為一行記錄中除主鍵外的資料。對於不同的記錄,key值互不相同。

B-Tree中的每個節點根據實際情況可以包含大量的關鍵字資訊和分支,如下圖所示為一個3階的B-Tree:

每個節點佔用一個盤塊的磁碟空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指標,指標儲存的是子節點所在磁碟塊的地址。兩個鍵將資料劃分成的三個範圍域,對應三個指標指向的子樹的資料的範圍域。以根節點為例,關鍵字為17和35,P1指標指向的子樹的資料範圍為小於17,P2指標指向的子樹的資料範圍為17~35,P3指標指向的子樹的資料範圍為大於35。

模擬查詢關鍵字29的過程:

  1. 根據根節點找到磁碟塊1,讀入記憶體。【磁碟I/O操作第1次】
  2. 比較關鍵字29在區間(17,35),找到磁碟塊1的指標P2
  3. 根據P2指標找到磁碟塊3,讀入記憶體。【磁碟I/O操作第2次】
  4. 比較關鍵字29在區間(26,30),找到磁碟塊3的指標P2
  5. 根據P2指標找到磁碟塊8,讀入記憶體。【磁碟I/O操作第3次】
  6. 在磁碟塊8中的關鍵字列表中找到關鍵字29

分析上面過程,發現需要3次磁碟I/O操作,和3次記憶體查詢操作,由於記憶體中的關鍵字是一個有序表結構,可以利用二分法快速定位到目標資料,而3次磁碟I/O操作是影響整個B-Tree查詢效率的決定因素。

B-樹相對於avl樹,通過在節點中增加節點內部資料的個數來減少磁碟的io操作。

上面我們說過mysql是採用頁方式來讀寫資料,每頁是16KB,我們用B-樹來儲存mysql的記錄,每個節點對應mysql中的一頁(16KB),假如每行記錄加上樹節點中的1個指標佔160Byte,那麼每個節點可以儲存1000(16KB/160byte)條資料,樹的高度為3的節點大概可以儲存(第一層1000+第二層$1000^{2}$+第三層$1000^{3}$)10億條記錄,是不是非常驚訝,一個高度為3個B-樹大概可以儲存10億條記錄,我們從10億記錄中查詢資料只需要3次io操作可以定位到目標資料所在的頁,而頁內部的資料又是有序的,然後將其載入到記憶體中用二分法查詢,是非常快的。

可以看出使用B-樹定位某個值還是很快的(10億資料中3次io操作+記憶體中二分法),但是也是有缺點的:B-不利於範圍查詢,比如上圖中我們需要查詢[15,36]區間的資料,需要訪問7個磁碟塊(1/2/7/3/8/4/9),io次數又上去了,範圍查詢也是我們經常用到的,所以b-樹也不太適合在磁碟中儲存需要檢索的資料。

b+樹

先看個b+樹結構圖:

b+樹的特徵

  1. 每個結點至多有m個子女
  2. 除根結點外,每個結點至少有[m/2]個子女,根結點至少有兩個子女
  3. 有k個子女的結點必有k個關鍵字
  4. 父節點中持有訪問子節點的指標
  5. 父節點的關鍵字在子節點中都存在(如上面的1/20/35在每層都存在),要麼是最小值,要麼是最大值,如果節點中關鍵字是升序的方式,父節點的關鍵字是子節點的最小值
  6. 最底層的節點是葉子節點
  7. 除葉子節點之外,其他節點不儲存資料,只儲存關鍵字和指標
  8. 葉子節點包含了所有資料的關鍵字以及data,葉子節點之間用連結串列連線起來,可以非常方便的支援範圍查詢

b+樹與b-樹的幾點不同

  1. b+樹中一個節點如果有k個關鍵字,最多可以包含k個子節點(k個關鍵字對應k個指標);而b-樹對應k+1個子節點(多了一個指向子節點的指標)
  2. b+樹除葉子節點之外其他節點值儲存關鍵字和指向子節點的指標,而b-樹還儲存了資料,這樣同樣大小情況下,b+樹可以儲存更多的關鍵字
  3. b+樹葉子節點中儲存了所有關鍵字及data,並且多個節點用連結串列連線,從上圖中看子節點中資料從左向右是有序的,這樣快速可以支撐範圍查詢(先定位範圍的最大值和最小值,然後子節點中依靠連結串列遍歷範圍資料)

B-Tree和B+Tree該如何選擇?

  1. B-Tree因為非葉子結點也儲存具體資料,所以在查詢某個關鍵字的時候找到即可返回。而B+Tree所有的資料都在葉子結點,每次查詢都得到葉子結點。所以在同樣高度的B-Tree和B+Tree中,B-Tree查詢某個關鍵字的效率更高。
  2. 由於B+Tree所有的資料都在葉子結點,並且結點之間有指標連線,在找大於某個關鍵字或者小於某個關鍵字的資料的時候,B+Tree只需要找到該關鍵字然後沿著連結串列遍歷就可以了,而B-Tree還需要遍歷該關鍵字結點的根結點去搜索。
  3. 由於B-Tree的每個結點(這裡的結點可以理解為一個數據頁)都儲存主鍵+實際資料,而B+Tree非葉子結點只儲存關鍵字資訊,而每個頁的大小有限是有限的,所以同一頁能儲存的B-Tree的資料會比B+Tree儲存的更少。這樣同樣總量的資料,B-Tree的深度會更大,增大查詢時的磁碟I/O次數,進而影響查詢效率。

Mysql的儲存引擎和索引

mysql內部索引是由不同的引擎實現的,主要說一下InnoDB和MyISAM這兩種引擎中的索引,這兩種引擎中的索引都是使用b+樹的結構來儲存的。

InnoDB中的索引

Innodb中有2種索引:主鍵索引(聚集索引)、輔助索引(非聚集索引)。

主鍵索引:每個表只有一個主鍵索引,葉子節點同時儲存了主鍵的值也資料記錄。

輔助索引:葉子節點儲存了索引欄位的值以及主鍵的值。

MyISAM引擎中的索引

不管是主鍵索引還是輔助索引結構都是一樣的,葉子節點儲存了索引欄位的值以及資料記錄的地址。

如下圖:

有一張表,Id作為主索引,Name作為輔助索引。

InnoDB資料檢索過程

如果需要查詢id=14的資料,只需要在左邊的主鍵索引中檢索就可以了。

如果需要搜尋name='Ellison'的資料,需要2步:

  1. 先在輔助索引中檢索到name='Ellison'的資料,獲取id為14
  2. 再到主鍵索引中檢索id為14的記錄

輔助索引這個查詢過程在mysql中叫做回表。

MyISAM資料檢索過程

  1. 在索引中找到對應的關鍵字,獲取關鍵字對應的記錄的地址
  2. 通過記錄的地址查詢到對應的資料記錄

我們用的最多的是innodb儲存引擎,所以此處主要說一下innodb索引的情況,innodb中最好是採用主鍵查詢,這樣只需要一次索引,如果使用輔助索引檢索,涉及到回表操作,比主鍵查詢要耗時一些。

innodb中輔助索引為什麼不像myisam那樣儲存記錄的地址?

表中的資料發生變更的時候,會影響其他記錄地址的變化,如果輔助索引中記錄資料的地址,此時會受影響,而主鍵的值一般是很少更新的,當頁中的記錄發生地址變更的時候,對輔助索引是沒有影響的。

我們來看一下mysql中頁的結構,頁是真正儲存記錄的地方,對應B+樹中的一個節點,也是mysql中讀寫資料的最小單位,頁的結構設計也是相當有水平的,能夠加快資料的查詢。

頁結構

mysql中頁是innodb中儲存資料的基本單位,也是mysql中管理資料的最小單位,和磁碟互動的時候都是以頁來進行的,預設是16kb,mysql中採用b+樹儲存資料,頁相當於b+樹中的一個節點。

頁的結構如下圖:

每個Page都有通用的頭和尾,但是中部的內容根據Page的型別不同而發生變化。Page的頭部裡有我們關心的一些資料,下圖把Page的頭部詳細資訊顯示出來:

我們重點關注和資料組織結構相關的欄位:Page的頭部儲存了兩個指標,分別指向前一個Page和後一個Page,根據這兩個指標我們很容易想象出Page連結起來就是一個雙向連結串列的結構,如下圖:

再看看Page的主體內容,我們主要關注行資料和索引的儲存,他們都位於Page的User Records部分,User Records佔據Page的大部分空間,User Records由一條一條的Record組成。在一個Page內部,單鏈表的頭尾由固定內容的兩條記錄來表示,字串形式的"Infimum"代表開頭,"Supremum"代表結尾,這兩個用來代表開頭結尾的Record儲存在System Records的,Infinum、Supremum和User Records組成了一個單向連結串列結構。最初資料是按照插入的先後順序排列的,但是隨著新資料的插入和舊資料的刪除,資料物理順序會變得混亂,但他們依然通過連結串列的方式保持著邏輯上的先後順序,如下圖:

把User Record的組織形式和若干Page組合起來,就看到了稍微完整的形式。

innodb為了快速查詢記錄,在頁中定義了一個稱之為page directory的目錄槽(slots),每個槽位佔用兩個位元組(用於儲存指向記錄的地址),page directory中的多個slot組成了一個有序陣列(可用於二分法快速定位記錄,向下看),行記錄被Page Directory邏輯的分成了多個塊,塊與塊之間是有序的,能夠加速記錄的查詢,如下圖:

看上圖,每個行記錄的都有一個n_owned的區域(圖中粉色區域),n_owned標識所屬的slot這個這個塊有多少條資料,偽記錄Infimum的n_owned值總是1,記錄Supremum的n_owned的取值範圍為[1,8],其他使用者記錄n_owned的取值範圍[4,8],並且只有每個塊中最大的那條記錄的n_owned才會有值,其他的使用者記錄的n_owned為0。

資料檢索過程

在page中查詢資料的時候,先通過b+樹中查詢方法定位到資料所在的頁,然後將頁內整體載入到記憶體中,通過二分法在page directory中檢索資料,縮小範圍,比如需要檢索7,通過二分法查詢到7位於slot2和slot3所指向的記錄中間,然後從slot3指向的記錄5開始向後向後一個個找,可以找到記錄7,如果裡面沒有7,走到slot2向的記錄8結束。

n_owned範圍控制在[4,8]內,能保證每個slot管轄的範圍內資料量控制在[4,8]個,能夠加速目標資料的查詢,當有資料插入的時候,page directory為了控制每個slot對應塊中記錄的個數([4,8]),此時page directory中會對slot的數量進行調整。

對page的結構總結一下

  1. b+樹中葉子頁之間用雙向連結串列連線的,能夠實現範圍查詢
  2. 頁內部的記錄之間是採用單向連結串列連線的,方便訪問下一條記錄
  3. 為了加快頁內部記錄的查詢,對頁內記錄上加了個有序的稀疏索引,叫頁目錄(page directory)

整體上來說mysql中的索引用到了b+樹,連結串列,二分法查詢,做到了快速定位目標資料,快速範圍查詢。

本篇到此,下一篇實戰篇對mysql索引使用上面做詳細介紹,喜歡的關注一下,謝謝!

Mysql系列目錄

  1. 第1篇:mysql基礎知識
  2. 第2篇:詳解mysql資料型別(重點)
  3. 第3篇:管理員必備技能(必須掌握)
  4. 第4篇:DDL常見操作
  5. 第5篇:DML操作彙總(insert,update,delete)
  6. 第6篇:select查詢基礎篇
  7. 第7篇:玩轉select條件查詢,避免採坑
  8. 第8篇:詳解排序和分頁(order by & limit)
  9. 第9篇:分組查詢詳解(group by & having)
  10. 第10篇:常用的幾十個函式詳解
  11. 第11篇:深入瞭解連線查詢及原理
  12. 第12篇:子查詢
  13. 第13篇:細說NULL導致的神坑,讓人防不勝防
  14. 第14篇:詳解事務
  15. 第15篇:詳解檢視
  16. 第16篇:變數詳解
  17. 第17篇:儲存過程&自定義函式詳解
  18. 第18篇:流程控制語句
  19. 第19篇:遊標詳解
  20. 第20篇:異常捕獲及處理詳解
  21. 第21篇:什麼是索引?
  22. 第22篇:mysql索引原理詳解

mysql系列大概有20多篇,喜歡的請關注一下,歡迎大家加我微信itsoku或者留言交流mysql相關技術!

相關推薦

Mysql高手系列 - 22深入理解mysql索引原理連載

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第22篇。 背景 使用mysql最多的就是查詢,我們迫切的希望mysql能查詢的更快一些,我們經常用到的查詢有: 按照id查詢唯一一條

Mysql高手系列 - 11深入瞭解連線查詢及原理

這是Mysql系列第11篇。 環境:mysql5.7.25,cmd命令中進行演示。 當我們查詢的資料來源於多張表的時候,我們需要用到連線查詢,連線查詢使用率非常高,希望大家都務必掌握。 本文內容 笛卡爾積 內連線 外連線 左連線 右連線 表連線的原理 使用java實現連線查詢,加深理解 準備資料 2張表

Mysql高手系列 - 7玩轉select條件查詢避免踩坑

這是Mysql系列第7篇。 環境:mysql5.7.25,cmd命令中進行演示。 電商中:我們想檢視某個使用者所有的訂單,或者想檢視某個使用者在某個時間段內所有的訂單,此時我們需要對訂單表資料進行篩選,按照使用者、時間進行過濾,得到我們期望的結果。 此時我們需要使用條件查詢來對指定表進行操作,我們需要了解sq

Mysql高手系列 - 8詳解排序和分頁(order by & limit)及存在的坑

這是Mysql系列第8篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 本章內容 詳解排序查詢 詳解limit limit存在的坑 分頁查詢中的坑 排序查詢(order by) 電商中:我們想檢視今天所有成交的訂單,按照交易額從高到低排序

Mysql高手系列 - 9詳解分組查詢mysql分組有大坑!

這是Mysql系列第9篇。 環境:mysql5.7.25,cmd命令中進行演示。 本篇內容 分組查詢語法 聚合函式 單欄位分組 多欄位分組 分組前篩選資料 分組後篩選資料 where和having的區別 分組後排序 where & group by & having & order

Mysql高手系列 - 10常用的幾十個函式詳解收藏慢慢看

這是Mysql系列第10篇。 環境:mysql5.7.25,cmd命令中進行演示。 MySQL 數值型函式 函式名稱 作 用 abs 求絕對值 sqrt 求二次方根 mod 求餘數 ceil 和 ceiling 兩個函式功能相同,都是返回不小於引數的最小整數,即向上取整 floo

Mysql高手系列 - 12子查詢詳解

這是Mysql系列第12篇。 環境:mysql5.7.25,cmd命令中進行演示。 本章節非常重要。 子查詢 出現在select語句中的select語句,稱為子查詢或內查詢。 外部的select查詢語句,稱為主查詢或外查詢。 子查詢分類 按結果集的行列數不同分為4種 標量子查詢(結果集只有一行一列) 列子查

Mysql高手系列 - 13細說NULL導致的神坑讓人防不勝防

這是Mysql系列第13篇。 環境:mysql5.7.25,cmd命令中進行演示。 當資料的值為NULL的時候,可能出現各種意想不到的效果,讓人防不勝防,我們來看看NULL導致的各種神坑,如何避免? 比較運算子中使用NULL 認真看下面的效果 mysql> select 1>NULL; +--

Mysql高手系列 - 14詳解事務

這是Mysql系列第14篇。 環境:mysql5.7.25,cmd命令中進行演示。 開發過程中,會經常用到資料庫事務,所以本章非常重要。 本篇內容 什麼是事務,它有什麼用? 事務的幾個特性 事務常見操作指令詳解 事務的隔離級別詳解 髒讀、不可重複讀、可重複讀、幻讀詳解 演示各種隔離級別產生的現象 關於隔離級

Mysql高手系列 - 21什麼是索引

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第21篇。 本文開始連續3篇詳解mysql索引: 第1篇來說說什麼是索引? 第2篇詳解Mysql中索引的原理 第3篇結合索引詳解關鍵字explain 本文為索引第一篇:我們來了解一下什麼是索引? 路人在搞

Mysql高手系列 - 18mysql流程控制語句詳解(高手進階)

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第18篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 上一篇儲存過程&自定義函式,對儲存過程和自定義函式做了一個簡單的介紹,但是如

Mysql高手系列 - 19mysql遊標詳解此技能可用於救火

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第19篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 需求背景 當我們需要對一個select的查詢結果進行遍歷處理的時候,如何實現呢? 此

Mysql高手系列 - 20異常捕獲及處理詳解(實戰經驗)

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 這是Mysql系列第20篇。 環境:mysql5.7.25,cmd命令中進行演示。 程式碼中被[]包含的表示可選,|符號分開的表示可選其一。 需求背景 我們在寫儲存過程的時候,可能會出現下列一些情況: 插入的資料違反唯一約束

Mysql高手系列 - 24如何正確的使用索引?【高手進階】

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第24篇。 學習索引,主要是寫出更快的sql,當我們寫sql的時候,需要明確的知道sql為什麼會走索引?為什麼有些sql不走索引?sql

Mysql高手系列 - 26聊聊如何使用mysql實現分散式鎖

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第26篇。 本篇我們使用mysql實現一個分散式鎖。 分散式鎖的功能 分散式鎖使用者位於不同的機器中,鎖獲取成功之後,才可以對共享資源

Mysql高手系列 - 27mysql如何確保資料不丟失的?我們借鑑這種設計思想實現熱點賬戶高併發設計及跨庫轉賬問題

Mysql系列的目標是:通過這個系列從入門到全面掌握一個高階開發所需要的全部技能。 歡迎大家加我微信itsoku一起交流java、演算法、資料庫相關技術。 這是Mysql系列第27篇。 本篇文章我們先來看一下mysql是如何確保資料不丟失的,通過本文我們可以瞭解mysql內部確保資料不丟失的原理,學習裡面優秀

Mysql高手系列 - 4天DDL常見操作彙總

這是Mysql系列第4篇。 環境:mysql5.7.25,cmd命令中進行演示。 DDL:Data Define Language資料定義語言,主要用來對資料庫、表進行一些管理操作。 如:建庫、刪庫、建表、修改表、刪除表、對列的增刪改等等。 文中涉及到的語法用[]包含的內容屬於可選項,下面做詳細說明。 庫的管

Mysql高手系列 - 5天DML操作彙總確定你都會?

這是Mysql系列第5篇。 環境:mysql5.7.25,cmd命令中進行演示。 DML(Data Manipulation Language)資料操作語言,以INSERT、UPDATE、DELETE三種指令為核心,分別代表插入、更新與刪除,是必須要掌握的指令,DML和SQL中的select熟稱CRUD(增刪

java高併發系列 - 22java底層工具類Unsafe高手必須要了解

這是java高併發系列第22篇文章,文章基於jdk1.8環境。 本文主要內容 基本介紹 通過反射獲取Unsafe例項 Unsafe中的CAS操作 Unsafe中原子操作相關方法介紹 Unsafe中執行緒排程相關方法 park和unpark示例 Unsafe鎖示例 Unsafe中保證變數的可見性 Unsafe

Python金融系列現代投資組合理論

作者:chen_h 微訊號 & QQ:862251340 微信公眾號:coderpai 第一篇:計算股票回報率,均值和方差 第二篇:簡單線性迴歸 第三篇:隨機變數和分佈 第四篇:置信區間和假設檢驗 第五篇:多元線性迴歸和殘差分析 第六篇:現代投資組合