自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

高并發(fā)之存儲篇:關注下索引原理和優(yōu)化吧!躲得過實踐,躲不過面試官!

數據庫 MySQL
本文從MySQL的存儲結構、索引的設計思路演進、美團阿里大型系統索引使用等幾個部分,闡述了索引的原理和對業(yè)務系統的重要作用。

不管是啥業(yè)務,最終數據都要落地,數據庫這一環(huán)是肯定少不了的。隨著業(yè)務發(fā)展,并發(fā)越來越高,數據庫很容易成為整個鏈路的短板。這也是大廠面試中比較常被問到的。而調優(yōu)的第一步,都是從sql語句、索引入手。先得保證單個數據庫執(zhí)行沒問題,才會有更高層次的分庫分表、彈性、容災等等。

Part1為什么Kafka不需要我們關心索引,而Mysql卻需要?

Kafka 和 MySQL 雖然最終數據都是落磁盤,但是兩者在用途和數據查詢方式上有著很大的差異,所以決定了數據的存儲結構不同,進而決定了索引的復雜程度。

我們先看下kafka的存儲結構:

由于 kafka 的定位是進行穩(wěn)定的高性能數據讀寫。所以對磁盤來說,是采用順序讀寫的方式,落在了一些 .log 文件中,并以基準偏移量補0命名。

為了實現高速查找 kafka 創(chuàng)建了稀疏索引文件(隔一段數據創(chuàng)建一條,而非全量),即index文件。其中維護消息的 offset 和 .log文件的物理位置。通過二分查找快速定位log文件并順序掃描找到目標。

所以,kafka的索引組織方式是相對簡單、方案相對固定,但MySQL卻不行。Mysql是關系型數據庫,是為了支持復雜的業(yè)務數據查詢而創(chuàng)建的,查詢方式、數據獲取需求多種多樣,要求MySQL具備更加復雜的索引機制來加速復雜業(yè)務查詢場景。

Part2MySQL數據怎么被組織[1][2]

以InnoDB存儲引擎來看mysql數據存儲:

參考了三本資料,基本把最重要的部分都概括了

數據被分了多個邏輯層:行->頁->區(qū)塊->段->表空間。

我們知道,InnoDB存儲引擎表是Index organized的(數據即索引,索引即數據),他們都維護在一個B+樹上,數據段就是葉子節(jié)點,索引段就是非葉子節(jié)點;

而我們劃分的段、區(qū)塊 其實都是為了利用操作系統的資源(比如每次從磁盤加載到內存的數據大小按區(qū)塊來約定等等`)來達到更高效讀寫的目的,邏輯劃分的。

其中頁是MySQL和磁盤交互的最小單位,怎么從頁找到行,怎么聚合到塊、到段再到空間呢。

1數據記錄最小單位-- 行

從上面總圖中摘出一條記錄的結構如下圖:

我們可以看到,記錄頭中除了行號,還有下一條記錄的標識next_record,所以,我們可以通過next_record將記錄連接起來,以單向鏈表的形式,所以這就決定了,當我們在記錄鏈中尋找某記錄時,只能順序遍歷,這也決定了一條數據鏈不會太長。

但一個頁默認是16K,加上行溢出等處理,一頁最多存放7992行記錄,這么多的記錄,必須順序遍歷么?當然不需要,讓我看看頁是怎么組織記錄行的。

2與磁盤最小交互單位-- 頁

作為與磁盤交互的最小單位,是用來存放實際數據的(頁類型是b-tree Node存真實數據,還有其他類型如索引目錄頁等用來加速查詢)從上面的大圖中可以大致看到一個頁的整體結構:

讓我們來看幾個關鍵的字段參數:

Page Directory 決定著記錄項在頁內的查詢效率

為了更快速的查詢,頁目錄存儲的本頁的數據目錄(槽),包含最大最小記錄和 分組數據鏈的最大記錄的偏移量。方便使用二分法快速查找數據,不需要再從最小值開始遍歷,如下圖:

圖片來自《從根兒上理解 MySQL》

File Header決定頁和頁之間怎樣關聯

記錄本頁的一些通用信息,主要包含< 本頁頁號、上一頁、下一頁、頁類型、所屬表空間等等>。

通過頁號來找到本頁、通過上下頁進行雙向鏈表串聯、通過類型判斷是索引頁還是數據頁。。。

圖片來自《從根兒上理解 MySQL》

此字段決定了頁和頁之間可以很方便的通過上述屬性進行關聯。

Page Header決定頁的層級

存儲的本頁的數據信息,主要包含**<** 本頁記錄數量、在B+樹中的層級、歸屬的索引ID、插入方向、最大事務ID等等 >。

有了頁面的數據組織概念,那么,怎么利用這些結構來實現的數據快速查詢呢?

Part3索引的演進思路

從上面的數據組織的知識里可以看到,行記錄之間串聯成單向鏈表,在每頁中都按分組方式分布在此頁的最小記錄和最大記錄之間。

頁面之間通過上一頁、下一頁的指針,串聯成雙向鏈表,在磁盤中進行存儲,如下圖:

那么,要查詢一條記錄,可以怎么做?

3原始:順序方式

如上圖所示的數據串聯方式,自然的提供了一種查詢方式:即按主鍵順序遍歷每頁和頁中的記錄行。

但是,這樣的查詢方式,除了在頁內有二分優(yōu)化,再無效率可言。怎么辦?

尋求改進:既然頁內的行記錄可以分組入槽,那數據頁之間為什么不行呢?

4改進:目錄方式

我們將頁向上聚蔟,構建一個頁號目錄,先在目錄中查找,再到對應頁中查找,就比順序查找要快很多了。

尋求改進:這樣的方式所需大量連續(xù)空間 + 目錄會隨數據變動而頻繁變動,怎么辦?

5演進:主鍵B+樹方式

其實,在敘述行記錄結構的時候,我們就看到,數據行的結構中,除了實際業(yè)務數據外,還有很多額外空間。

如record_type用來表示該記錄的類型是數據還是索引。正是這些額外的空間的設計,給InnoDB以更加適合的方式組織索引提供了支持:

圖片來自《從根兒上理解 MySQL》

這就是一棵B+樹,頁節(jié)點有層級區(qū)分,頁中的行記錄有類型區(qū)分。

業(yè)務數據都包含在葉子節(jié)點中,目錄數據都包含在其他非葉節(jié)點中。

這樣組織方式的優(yōu)勢,是允許足夠少的層級容納足夠多的數據項(可以簡單的假設每一頁的數據項大小來預估)。

而這個索引方式就是我們常說的聚蔟索引。即使用主鍵值進行記錄和頁的排序,且葉子節(jié)點含有全部用戶數據。

尋求改進:如果我想用其他列來查詢,怎么辦?

6擴展:二級索引、聯合索引

二級索引

比如用戶需要根據某一列(a列)的值來查詢,那就再重新創(chuàng)建一個B+樹。此索引樹和聚蔟索引樹的差別在于,索引節(jié)點是以a列的值為目錄,且葉子節(jié)點只包含a列的值和主鍵兩個值。

如果用戶需要查詢除c列以外的更多信息,則需要拿主鍵ID再去聚蔟索引查一次,也叫回表。

聯合索引

二級索引是除主鍵外的單列索引,而聯合索引則是多個列共同排序。假設用戶需要用a 、b 兩個列進行有序查詢,那內在含義是,在a列值相同的情況下,再判斷b的值。

同二級索引一樣,InnoDB也需要再創(chuàng)建一棵B+樹,且目錄項的排序按先a,后b進行排序串聯,葉子節(jié)點的數據項只包含 a 、b、主鍵三個值。

Part4生產實踐之觸類旁通

7美團定時任務索引優(yōu)化[3]

系統需要定時的撈取特定時間段內特定狀態(tài)、特定類型、特定操作者的任務進行定時處理。 

  1. select * from task   
  2. where  
  3.    status=x  
  4.    and operator_id=xxxx   
  5.    and operate_time>xxxxxxxx01  
  6.    and operate_time<xxxxxxxx99  
  7.    and type=x

開發(fā)發(fā)現此sql運行的越來越慢,希望給每個字段加二級索引,被優(yōu)化師叫停,而是考慮的該表所有查詢方式后,創(chuàng)建了一個聯合索引: 

  1. (status,operator_id,type,operate_time) 

為什么不建多個的二級索引?為什么范圍查詢的字段要放在最后?

分析:

(1)從前面的原理部分我們知道,索引是要占內存的,不是越多越好,能起作用就行。

(2)用于范圍匹配的字段的索引位置要嚴謹。因為創(chuàng)建索引的時候,根據索引字段的順序來進行排序,如果把time字段放在type字段前面建索引,在查詢時,因為time是一個范圍值,那么多個time值延續(xù)到type字段,整體是無序的,無法用到type索引。

8螞蟻分布式主事務表的索引運用

螞蟻的分布式事務中的主事務表起到了維護整體事務狀態(tài)的作用,其中包含了整體事務狀態(tài)、操作時間等字段。而在業(yè)務支付發(fā)生異常,且實時回滾失敗時,需要事務恢復系統從遠程撈取前1分鐘的異常數據,并撈取對應的分支記錄表發(fā)起異步回滾。

考慮查詢效率,查詢sql會限定業(yè)務發(fā)生時間在[前10分鐘,前1分鐘],是有范圍查詢,所以,針對其他字段,業(yè)務時間的索引順序需要置于聯合索引的最后。此操作的原理和上一部分美團定時任務的原理是一樣的。

9阿里開發(fā)手冊中幾條典型的規(guī)范[4]

【強制】 在 varchar 字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據實際文本區(qū)分度決定索引長度。

原理關聯:字段越長,索引占內存越多,只要其長度可以保證區(qū)分度即可

【強制】 字符搜索嚴禁左模糊或者全模糊,如果需要請走搜索引擎來解決。

原理關聯:左模糊的字段不是有序的,無法用到索引

【推薦】 如果有 order by 的場景,請注意利用索引的有序性。order by 最后的字段是組合索引的一部分,并且放在索引組合順序的最后,避免出現 file_sort 的情況,影響查詢性能。

原理關聯:如果條件中有范圍查詢,則后續(xù)字段是無序的,order by時無法用到索引

【推薦】 建組合索引的時候,區(qū)分度最高的在最左邊。

原理關聯:區(qū)分度越高,查詢路徑越短,效率越高

等等,參見阿里Java開發(fā)手冊

Part5總結

本文從MySQL的存儲結構、索引的設計思路演進、美團阿里大型系統索引使用等幾個部分,闡述了索引的原理和對業(yè)務系統的重要作用。

當然,對于高并發(fā)下的數據庫的優(yōu)化遠不止索引優(yōu)化這一個方面,本文只從索引這一個點出發(fā),讓大家對其優(yōu)化原理和優(yōu)化方向有一個大致的概念,在業(yè)務發(fā)展遇到數據庫瓶頸時能有所幫助。 

 

責任編輯:龐桂玉 來源: Coder的技術之路
相關推薦

2020-10-15 06:26:24

高并發(fā)場景冰河

2024-09-25 12:26:14

2023-10-13 00:00:00

并發(fā)樂觀鎖CAS

2024-08-22 10:39:50

@Async注解代理

2024-03-05 10:33:39

AOPSpring編程

2025-03-07 00:00:10

2020-12-09 10:29:53

SSH加密數據安全

2022-02-11 19:06:29

MySQL索引面試官

2022-03-21 09:05:18

volatileCPUJava

2022-09-29 07:30:57

數據庫索引字段

2022-09-07 08:25:08

代理模式設計模式代碼

2022-09-05 08:17:57

JPA級聯java

2024-02-28 10:14:47

Redis數據硬盤

2025-03-26 01:25:00

MySQL優(yōu)化事務

2024-03-07 17:21:12

HotSpotJVMHot Code

2024-02-29 16:49:20

volatileJava并發(fā)編程

2024-11-19 15:13:02

2024-08-29 16:30:27

2023-12-27 18:16:39

MVCC隔離級別幻讀

2025-04-16 00:00:01

JWT客戶端存儲加密令
點贊
收藏

51CTO技術棧公眾號