1. 程式人生 > 遊戲攻略 >《永劫無間》長槍連招教學

《永劫無間》長槍連招教學

目的

使以下查詢速度更快:

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

本質

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

頁與磁碟

磁碟塊:檔案系統與磁碟互動的最小單位,一個磁碟塊由連續幾個扇區組成,一般大小為4KB

頁:MySQL中和磁碟互動的最小單位稱為頁,是一種資料結構,預設為16KB,相當於4個磁碟塊。

B-樹和B+樹

區別

  1. B+樹除葉子節點之外其他節點值儲存關鍵字和指向子節點的指標,B-樹還儲存了資料,同樣大小情況下,B+樹可以儲存更多的關鍵字
  2. B+樹葉子節點中儲存了所有關鍵字和data,並且多個節點用連結串列連線,子節點從左到右是有序的,可以支援範圍查詢。

如何選擇

  1. B-樹非葉子節點也儲存資料,在查詢某個關鍵字的時候找到即可返回。在同樣高度的兩種樹中,B-樹查詢某個關鍵字的效率更高。
  2. 在找大於某個關鍵字或者小於某個關鍵字的資料的時候,B+樹只需要找到該關鍵字然後沿著連結串列遍歷即可,但B-樹需要遍歷該關鍵字結點的根結點去搜索。
  3. 同樣總量的資料,B-樹的深度會更大,增大查詢時的磁碟I/O次數,進而影響查詢效率。

MySQL的儲存引擎和索引

InnoDB

兩種索引

主鍵索引/聚集:每個表只有一個主鍵索引,葉子節點同時儲存主鍵的值和資料

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

輔助索引查詢的過程叫回表:先在輔助索引中檢索到資料,獲取id,然後通過id在主鍵索引中檢索。

MyISAM

兩種索引的葉子節點儲存了索引欄位的值以及資料記錄的地址。

過程:在索引中找到關鍵字,獲取地址,通過地址找到資料。

為什麼InnoDB的輔助索引不存地址?

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

索引分類

  • 主鍵索引

    每個表都會有,整個表的資料儲存在聚集索引中,B+樹,非葉子節點存主鍵的值,葉子節點存主鍵的值+記錄的資料

    表中未指定主鍵時,自動給每條記錄新增隱藏的rowid欄位作為主鍵

    聚集索引

  • 輔助索引

    非聚集索引

    b+樹,非葉子節點存索引欄位,葉子節點存索引欄位和主鍵的值

    • 單列索引:一個索引只包含一個列
    • 多列索引(複合索引):一個索引包含多個列
    • 唯一索引:索引列的值必須唯一,允許有一個空值

CREATE [UNIQUE] INDEX 索引名稱 ON 表名(列名);

SHOW INDEX FROM 表名; 檢視索引資訊

EXPLAIN select * from test1 where sex=2 and name='javacode3500000';

最左匹配原則

當b+樹的資料項是複合的資料結構,比如(name,age,sex)的時候,b+樹是按照從左到右的順序來建立搜尋樹的,比如當(張三,20,F)這樣的資料來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最後得到檢索的資料;但當(20,F)這樣的沒有name的資料來的時候,b+樹就不知道下一步該查哪個節點,因為建立搜尋樹的時候name就是第一個比較因子,必須要先根據name來搜尋才能知道下一步去哪裡查詢。比如當(張三,F)這樣的資料來檢索時,b+樹可以用name來指定搜尋方向,但下一個欄位age的缺失,所以只能把名字等於張三的資料都找到,然後再匹配性別是F的資料了, 這個是非常重要的性質,即索引的最左匹配特性。

eg:

按照[a,c]兩個欄位查詢

這種只能利用到索引中的a欄位了,通過a確定索引範圍,然後載入a關聯的所有記錄,再對c的值進行過濾。

查詢a=1 and b>=0 and c=1的記錄

這種情況只能先確定a=1 and b>=0所在頁的範圍,然後對這個範圍的所有頁進行遍歷,c欄位在這個查詢的過程中,是無法確定c的資料在哪些頁的,此時我們稱c是不走索引的,只有a、b能夠有效的確定索引頁的範圍。

類似這種的還有>、<、between and,多欄位索引的情況下,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配。

索引區分度

索引區分度 = count(distinct 記錄) / count(記錄)

當索引區分度高的時候,檢索資料更快一些,索引區分度太低,說明重複的資料比較多,檢索的時候需要訪問更多的記錄才能夠找到所有目標資料。

當索引區分度非常小的時候,基本上接近於全索引資料的掃描了,此時查詢速度是比較慢的。

建立索引時,儘量選擇區分度高的列。

當多個條件中有索引的時候,並且關係是and的時候,會走索引區分度高的

覆蓋索引

查詢的內容只包含索引欄位+id,這個時候在進行輔助索引的檢索的時候,就已經可以得到select的全部資料,就不需要進行回表繼續檢索主鍵索引。

所以寫sql的時候,儘量避免使用**可能會多一次回表操作,需要看一下是否可以使用索引覆蓋來實現,效率更高一些。

索引下推

ICP(Index Condition Pushdown),MySQL5.6的新特性,使用索引過濾資料的一種優化方式,減少儲存引擎訪問及表的次數以及MySQL伺服器訪問儲存引擎的次數。

eg:

我們需要查詢name以javacode35開頭的,性別為1的記錄數,sql如下

select **count**(id) from test1 a where name like 'javacode35%' and sex = 1;

name為輔助索引的過程

  1. 走name索引檢索出以javacode35的第一條記錄,得到記錄的id
  2. 利用id去主鍵索引中查詢出這條記錄R1
  3. 判斷R1中的sex是否為1,然後重複上面的操作,直到找到所有記錄為止。

上面的過程中需要走name索引以及需要回表操作。

採用ICP的方式,建立一個(name,sex)的組合索引,查詢過程如下:

  1. 走(name,sex)索引檢索出以javacode35的第一條記錄,可以得到(name,sex,id),記做R1
  2. 判斷R1.sex是否為1,然後重複上面的操作,知道找到所有記錄為止

這個過程中不需要回表操作了,通過索引的資料就可以完成整個條件的過濾,速度比上面的更快一些。

使用索引的小tips

  1. 在區分度高的欄位上面建立索引可以有效的使用索引,區分度太低,無法有效的利用索引,可能需要掃描所有資料頁,此時和不使用索引差不多
  2. 聯合索引注意最左匹配原則:必須按照從左到右的順序匹配,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整
  3. 查詢記錄的時候,少使用*,儘量去利用索引覆蓋,可以減少回表操作,提升效率
  4. 有些查詢可以採用聯合索引,進而使用到索引下推(ICP),也可以減少回表操作,提升效率
  5. 禁止對索引欄位使用函式、運算子操作,會使索引失效
  6. 字串欄位和數字比較的時候會使索引無效
  7. 模糊查詢'%值%'會使索引無效,變為全表掃描,但是'值%'這種可以有效利用索引
  8. 排序中儘量使用到索引欄位,這樣可以減少排序,提升查詢效率