1. 程式人生 > 程式設計 >jvm調優的幾種場景(小結)

jvm調優的幾種場景(小結)

目錄

Mysql 索引

索引是幫助MySQL高效獲取資料的資料結構,,排好序的快速查詢資料結構
目的:減少磁碟I/O的次數,加快查詢速度

索引主要影響兩個位置:

  • 快速查詢(提高資料查詢效率):影響where後面的查詢
  • 排好序:order by

索引是在儲存引擎中實現的

優點
1.提高資料檢索的效率,降低資料庫的IO成本
2.建立唯一索引,保證資料庫表中每一行資料的唯一性
3.在使用分組和排序子句進行資料查詢時,可以減少查詢中分組和排序的時間,降低CPU的消耗

缺點
1.建立索引和維護索引要耗費時間,並且隨著資料量增加,所耗費的時間也會增加。
2.索引需要磁碟空間,一般索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存在磁碟中。
3.降低更新表的速度,當對錶中的資料進行增加、刪除和修改時,索引也要動態維護,這樣就降低了資料的維護速度

索引可以提高查詢的速度,但是會影響插入記錄的速度。這種情況下,最好的辦法是先刪除表中的索引,然後插入資料,插入完成後再建立索引。

InnoDB的索引模型

一個簡單的設計方案

CREATE TABLE index_demo(
	c1 INT,
	c2 INT,
	c3 CHAR(1),
	PRIMARY KEY(c1)
)ROW_FORMAT = Compact # 行格式表示每個記錄的格式ROW_FORMAT

Compact

record_type:
0 普通記錄
1 目錄項記錄
2 最小記錄
3 最大記錄

案例

假設每個資料頁最多存放3條記錄

INSER INTO index_demo VALUES(1,4,'u'),(5,3,'y'),(3,9,'d')

按主鍵從小到大的順序排列

此時資料頁10已經有三條記錄了,假設現在再插入一條記錄,那麼需要再分配一個數據頁

INSERT INTO index_deomo VALUES(4,4,'a')

假設現在需要查詢一條記錄,由於資料頁的編號可能是不連續的,所以查詢的時候可能需要每個資料頁都進去檢視一遍,效率是非常低的。

給每個頁建立一個目錄項

先在目錄項上查詢,然後再進入具體的資料頁查詢,這樣可以提高查詢效率

迭代一次:目錄項記錄的頁(目錄頁)

上述目錄項採用物理上連續的空間儲存(如陣列)
1.如果當目錄項個數很多時,可能並沒有足夠多的連續空間
2.當發生增刪改目錄項時,為了維持key有序,是非常麻煩的

目錄項也採用單項鍊表上連線,此時目錄項也構成了一個頁,稱為目錄頁

目錄項記錄和普通的使用者記錄的異同點

不同點 目錄項記錄 使用者記錄
record_type 1 0
儲存的內容 只有主鍵值和頁標號 使用者自定義的
min_rec_mask 只有目錄頁中主鍵最小的目錄項記錄為1,其餘都為0 0

相同點
都會為主鍵值生成Page Directory頁目錄,目的是為了使用二分法來加快查詢速度。

假設要查詢主鍵為20的記錄
1.先再目錄頁通過二分法查詢頁目錄,12<20<209,定位到記錄在頁9
2.到頁9的頁目錄中採用二分法快速找到主鍵值為20的使用者記錄

只有2次IO操作

迭代2次:目錄項記錄的多個頁

假設一個目錄頁已經記錄完了,就需要再分配一個新的儲存目錄項記錄的頁

如果要查詢某個記錄,就需要先使用二分法在頁30的目錄頁查詢,如果沒找到需要去頁32的頁目錄查詢

迭代3次:目錄項記錄頁的目錄頁

如果需要查詢的記錄在目錄頁的很後面,那需要多次的IO訪問

由於頁是不連續的,為了快速定位,我們需要在套一層目錄。這樣可以穩定IO訪問次數

B+ 樹能夠很好地配合磁碟的讀寫特性,減少的磁碟I/O操作的次數。
這個資料結構就是B+樹
1.只有葉子節點儲存資料
2.每一個父節點的元素都出現在子元素中,是子節點的最大(小)元素
3.葉子節點之間通過連結串列連線,

假設一個數據頁可以存放100條使用者記錄,一個目錄頁可以存放1000條目錄項記錄
B+樹有一層,可以存放100條記錄
B+樹有兩層,可以存放1000*100 = 10,0000條資料
B+樹有三層,可以存放1000*1000*100=1,0000,0000條資料
....

一般情況下,用到的B+樹都不會超過4層
1.已經可以儲存相當多的資料了
2.層數越低,訪問IO的次數越少

聚簇索引

索引分為:

  • 聚簇索引:由主鍵構建,聚簇表示記錄和目錄儲存在一起
  • 非聚簇索引/二級索引/輔助索引:由非主鍵構建,非聚簇是不儲存真正的資料的

所有完整的使用者記錄(包括隱藏列)都存放在聚簇索引的葉子節點處。InnoDB中不需要顯示的使用INDEX語句去建立聚簇索引,InnoDB儲存引擎會自動為我們建立聚簇索引

優點
1.訪問速度更快
2.聚簇索引對主鍵的排序查詢和範圍查詢速度非常快
3.按照聚簇索引排列順序,查詢一定範圍資料的時候,由於資料都是緊密相連的,資料庫不用從多個數據塊中提取資料,所以節省了IO操作

缺點
1.插入速度嚴重依賴插入順序,對於InnoDB表,我們一般會定義自增的ID列為主鍵
2.更新主鍵的代價很高,因為會導致主鍵被更新後行移動,對於InnoDB,我們一般定義主鍵不可更新
3.二級索引訪問需要兩次索引查詢,第一次查詢主鍵值,第二次根據主鍵值查詢行資料

儘量使用自增主鍵
NOT NULL PRIMARY KEY AUTO_INCREMENT
每次插入一條新記錄,都是追加操作,都不涉及到挪動其他記錄,也不會觸發葉子節點的分裂。
如果使用業務邏輯的欄位做主鍵,則往往不容易保證有序插入,這樣寫資料成本相對較高。

限制
1.MySQL資料庫中只有InnoDB資料引擎支援聚簇索引,而MyISAM並不支援聚簇索引
2.由於資料物理儲存方式只有一種,所以每個MySQL的表只能有一個聚簇索引
3.如果沒有定義主鍵,Innodb會選擇非空的唯一索引代替,如果沒有,Innodb會隱式定義一個索引來作為聚簇索引

二級索引(輔助索引、非聚簇索引)

假設c2列為索引,則葉子節點記錄c2的值和對應的主鍵值

每個索引對應一個B+樹
假設需要找c2=4的記錄,先在這顆B+樹上找到對應的主鍵為1,在去主鍵B+樹去找主鍵為1的記錄,這個過程稱為回表。

聯合索引

聯合索引同時為多個列建立索引,假設我們想讓B+樹按照c2和c3列的大小排序。會先按照c2進行排序,如果c2相同會按照c3列進行排序

InnoDB的B+樹索引的注意事項

  • 1 跟頁面位置萬年不動
  • 2 內節點中目錄項記錄的唯一性
  • 3 一個頁面最少儲存2條記錄

1 跟頁面位置萬年不動

為某個表建立一個B+樹索引(聚簇索引不是人為建立的,預設就有)的流程

1.為這個索引建立一個根節點頁面。最開始表中沒有資料的時候,每個B+樹索引對應的根節點中既沒有使用者記錄,也沒有目錄項記錄
2.向表中插入使用者記錄時,先把使用者記錄儲存到這個根節點中
3.當根節點中的空間用完時,繼續插入記錄,會將根節點的所有記錄複製到一個新分配的頁a,然後對新頁面進行頁分裂操作,得到一個新頁b。新記錄根據鍵值的大小會分配到頁a或頁b中,而根節點便升為目錄頁
4.當跟節點空間用完時,繼續插入記錄,會將跟節點的所有記錄複製到一個新分配的頁C,然後對新頁面進行頁分裂操作,得到一個新頁d,根節點便升為目錄頁的目錄頁

2 內節點中目錄項記錄的唯一性
主要針對二級索引

B+樹中目錄項記錄的內容是索引列+列號,對於二級索引來說不嚴謹。假設表中的資料是

保證B+樹的同一層內節點的目錄項記錄(除頁號,頁號肯定是不一樣的)是唯一的

所以對於二級索引的內節點的目錄項記錄的內容是由三個部分構成

  • 索引列的值
  • 主鍵值,保證唯一性
  • 頁號

二級索引的內節點的目錄項也保留了主鍵值

MyISAM與InnoDB的對比

主鍵索引和二級索引的結構都一樣

型別 MyISAM InnoDB
索引方式 非聚簇,無聚簇索引 包含1個聚簇索引,可以包含非聚簇索引
主鍵值查詢 相當於都是二級索引,所以會進行一次回表操作
主鍵的樹葉子節點沒有儲存記錄,儲存的是記錄的地址,去地址值找也算一次回表
主鍵值對聚簇索引進行一次查詢就能找到對應的記錄
資料檔案 索引檔案和資料檔案分離
索引檔案僅儲存資料記錄的地址
資料檔案按照新增順序,不需要排序
資料檔案本身就是索引檔案
回表操作 非常的快速,直接根據偏移量去檔案中取資料 速度慢一點
非聚簇索引data值 記錄的是地址 引用主鍵作為data域
主鍵 可以沒有 一定有

為什麼不適用Hash結構?

1.Hash索引僅滿足(=<>IN)查詢,進行範圍查詢的速度很慢,因為資料的儲存是無序的,如果在ORDER BY的情況下,還需要對資料重新排序

2.對應聯合索引,Hash值是將聯合索引鍵合併一起來計算,無法對單獨的一個鍵或幾個鍵進行查詢

3.對於等值查詢,通常Hash索引效率更高,但是查詢的Hash衝突的值過多時,效率回下降。

InnoDB本身不支援Hash索引,但是提供自適應Hash索引,如果某個資料經常被訪問,就會將這個資料頁的地址放到Hash表中,下次查詢時就可以直接找到這個頁面的所在位置。
採用自適應Hash索引可以根據SQL的查詢條件快速定位到葉子節點,尤其當B+樹比較深的時候,通過自適應Hash索引可以明顯提高資料的檢索效率。

通過innodb_adaptive_hash_index變數查詢是否開啟自適應Hashshow variables like'%adaptive_hash_index',預設時開啟的