索引概述

Ⅰ、什麼是索引

索引是一種提升數據庫查詢效率的數據結構(咱們說的通常都是B+ tree索引)html

(root@localhost) [test]> show create table l \G
*************************** 1. row ***************************
       Table: l
Create Table: CREATE TABLE `l` (
  `a` int(11) NOT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`),        -- 主鍵
  UNIQUE KEY `c` (`c`),     -- 惟一索引
  KEY `b` (`b`)             -- 普通索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.08 sec)

一張表能夠有多個索引,索引就是對建立索引的這些列進行排序
優勢:
使查詢速度變得很是快,且這個快基本上和數據量不要緊
缺點:
不少索引都要排序則要對這些索引列進行維護,直接插入原本很快,可是有了索引作ddl操做則代價比較大,雖然說不能太多索引列,可是大場景下很難作到mysql

tips:
主鍵和惟一索引的區別:sql

  • 一張表只能有一個主鍵,惟一索引能夠有多個
  • 主鍵不能夠爲NULL,惟一索引能夠

MySQL一張表的大小是多少?

不少人說一張表不能太大,太大要拆表?這麼說的兩個緣由(oracle沒這個說法):
a.MySQL以前的DDL操做,比較麻煩,建立了索引,再作這些會表鎖(全局讀鎖),數據量太大會鎖時間太長,也就是以前不支持online ddl嘛。之前都是先在slave上搞,搞好作個主從的切換
b.以前MySQL的索引源代碼的實現上有一把大鎖,致使性能比較通常,不過沒有淘寶這個業務量基本上影響不大,可是5.7也解決了這個問題數據庫

綜上:MySQL5.7這時候,索引自己已經實現地很完整了(管理和性能兩個方面),一億不是什麼問題數據結構

tips:併發

  • 大鎖:索引排序的時候作一個split的操做(也不會一直作split),拆分,原本把拆分的兩個頁鎖住便可,可是那時候是整個B+ tree鎖住了,併發性就受到影響比較大了,
  • 用MySQL就得上SSD,單表能承受1億根本不是什麼大問題,一個億和一千萬,查詢和維護代價基本上都是同樣的,五年前五百萬分表或許是適合的,如今就算了吧
  • sas盤的iops再怎麼優化也只有一千,拆了最可能是管理操做方便點,但也有問題,某個時間點數據不必定一致,好比某個時間點,這個表比另外一個表多一個列,sas五百萬或者一千萬差很少了,能夠作個raid10,ssd作raid5或者不作均可以
  • 電商平臺,快遞行業,一個月前的訂單,歸檔,用分區表來作,和性能不要緊,只是一個管理操做,也就是說分區表不是用來提高性能的,反而會降低,除非都走分區字段,可是線上查詢條件太多太多

再強調:
1.MySQL用SSDoracle

2.拆表不會提高性能工具

3.如今不存在最多多少記錄的問題性能

Ⅱ、B+ tree概述

2.1 B+ tree的定義

B+ tree是一種基於塊(page)設備的存儲中來有效的存取,檢索數據的數據結構優化

show variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
默認16k,oracle默認8k
看數據庫中.ibd文件,大小都是16k的倍數

tips:
文件系統都是基於塊的

db                          16k
-----------------------------------
filesystem(xfs)             4k 八個扇區 ,能夠調大提高性能
-----------------------------------
disk                        512字節

2.2 B+ tree的構成

  • root leaf
  • none leaf
    非葉子節點存放指針和鍵值
  • leaf
    葉子節點,用來排序的,存放每一行的完整記錄(頁子節點之間是有序的,頁子裏面記錄也是有序的)
  • fan out
    扇出,多少個指針,一個塊設備能存不少記錄,這時候扇出很是大,性能也很是好
    B+ tree基於塊設備存儲,一個頁能存很是多記錄,扇出很是高
  • 指針
    指向下一個層級,先找,找不到返回空

該B+ tree高度爲2,每一個葉子節點存放4條記錄,扇出數爲5,葉子節點由小到大有序

tips:
上面說的有序指的是邏輯有序,不是物理的,在磁盤上作不到有序,每一個頁之間有指針告訴他下一個頁和前一個頁,可是物理上可能跨了好幾個頁

Ⅲ、 B+ tree的維護

插入數據操做

如何插入28這條記錄?

先找28所在的頁,經過二分查找,找到指針指到的頁,若是頁中還有空閒就直接插

可是想插70,發現70所在的頁已經滿了,這時候就會作一個split操做(代價蠻大的),把這個頁拆成兩個頁,最經常使用的是把這個頁的中間值(這裏是60)提取出來放到上面,兩邊往下拆

插95呢,發現也滿了,想拆,可是發現上一層節點也滿了,因此要作兩次split

MySQL5.7以前split代價很是大,會把整棵樹都鎖住,這時候其餘記錄插入和更新就不方便了,可是一般分頁自己也仍是蠻快的額,也不會一直分頁,只是頁滿了的狀況纔會分,因此問題也不是很大,5.7不會一會兒鎖住,會盡可能用小的鎖控制併發
插入95以後B+ tree的高度從2變成了3

刪數據操做
若是一個頁裏面的數據不多了則會嘗試和它左邊或者右邊的頁進行合併

Ⅳ、索引實踐

alter table x add index unique idx_b (b);        -- 在b上建立一個惟一索引
alter table x add index index_a (a);             -- 在a上建立一個普通索引
alter table x drop index index_a;                -- 刪除a上面的索引

在線上就不同咯

還記得online ddl表嘛?

5.6以前建立索引並非online的,會對這個表加一個讀鎖(S lock)只能select不能insert,會阻塞

5.6開始原生支持了在線索引添加,在添加索引過程當中,應用程序對錶依然可讀可寫

online ddl的這段時間內,對錶作的操做會先記錄到alter table的日誌裏,這個日誌是內存的,若是內存大小過小記不下來就會報錯

(root@localhost) [(none)]> show variables like 'innodb_online_alter_log_max_size';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| innodb_online_alter_log_max_size | 134217728 |
+----------------------------------+-----------+
1 row in set (0.00 sec)

若是線上更新操做比較多,調大這個值set global innodb_online_alter_log_max_size = 128M,這是個全局變量,在my.cnf中也配上

在線索引添加存在的一個問題——主從延時(MySQL邏輯複製,oracle物理複製不存在這個問題)

alter table是執行完以後才告訴從機要執行(事務),從庫也順序執行,當執行到這個在線ddl,其餘並行的dml語句,也要等待這個ddl執行完畢後才能並行

同步的是二進制日誌,要等事務執行完以後才提交過去,並非物理日誌

真正在線上不多用alter table這種方式去執行ddl操做,即便5.7如今對愈來愈多的ddl操做讀寫不阻塞了,就是由於主從延時

如今就要percona toolkit出場了(備註,除了下面介紹的這個工具,裏面的其餘工具不建議使用,儘可能使用官方的)

這裏面最有用的就是pt-online-schema-change,其餘工具官方工具包utlities裏面都有了,官方也在作前面那個工具了

這個工具作在線ddl,主從延遲很是小,不是直接操做的,是經過觸發器的機制來慢慢加,還有控制延時的參數呢

關於online ddl和pt-osc詳見這裏

相關文章
相關標籤/搜索