MySql常見知識梳理

MySql簡介

數據庫系統(Database system)= 數據庫管理系統(DBMS,Database Management System)+數據庫(Database)

數據庫管理系統(DBMS)可分爲兩類:一類爲基於共享文件系統的DBMS,另一類爲基於客戶機-服務器的DBMS。

Mysql是最流行的關係型數據庫管理系統,在WEB應用方面MySQL是最好的RDBMS(Relational Database Management System:關係數據庫管理系統)應用軟件之一。

MySQL的優點:

  • MySQL是開源的,所以不需要支付額外的費用。

  • MySQLMysql支持大型的數據庫。可以處理擁有上千萬條記錄的大型數據庫。

  • MySQL使用標準的SQL數據語言形式。

  • MySQL可以允許於多個系統上,並且支持多種語言。這些編程語言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。

  • MySQL對PHP有很好的支持,PHP是目前最流行的Web開發語言。

  • MySQL支持大型數據庫,支持5000萬條記錄的數據倉庫,32位系統表文件最大可支持4GB,64位系統支持最大的表文件爲8TB。

  • MySQL是可以定製的,採用了GPL協議,你可以修改源碼來開發自己的Mysql系統。

數據庫對於JAVA開發的重要程度

  • 業務開發:懂基本SQL語句的編寫。

  • SQL優化:懂索引,懂引擎。

  • 分庫分表,懂主從,懂讀寫分離。

  • 安全,懂權限,懂備份,懂日誌

索引的概念,常見索引類型,索引的優缺點

在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。(百度百科)

從上面的定義中我們可以知道,索引是一種存儲結構;是數據庫表中一列或若干列值的集合,或者是指向表中數據頁物理標識的邏輯指針清單。

索引在數據庫中叫做鍵(Key),是存儲引擎用於快速找到記錄的一種數據結構,當表中數據量增大的時候,索引對性能的影響愈發重要,因此索引優化是查詢性能優化最有效的手段。

創建表:

CREATE TABLE `example_table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `name` varchar(10) NOT NULL COMMENT '姓名',
  `age` smallint(5) unsigned NOT NULL COMMENT '年齡',
  `card_id` smallint(5) unsigned NOT NULL COMMENT '學生卡號',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '表更新時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_card_id` (`card_id`),
  KEY `idx_age` (`age`,`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;

B-Tree索引(技術上的B+樹):對於上圖表中索引結構,給出可能的索引數據結構。

  1.  B-Tree可以加快訪問數據的速度,存儲引擎不會進行全表掃描而是從索引的根節點進行搜索,向下查找。
  2. B-Tree對索引列是按照順序存儲的,適合範圍查找。
  3. B-Tree索引對多個值的排序根據創建語句定義的順序查找,B-Tree索引只適用全鍵值,鍵值範圍或者鍵值前綴查找,鍵值前綴查找適合最左前綴查找。
    1. 全鍵值:比如查找age = 18, create_time = 2012-05-25 21:18:12 的人。
    2. 最左前綴:所有age = 18的人,只是用索引的第一列。
    3. 匹配列前綴:比如查詢age以1開始的所有人,也是隻索引的第一列。
    4. 匹配範圍: 比如age > 10 and age < 100的人,也只是索引的第一列。
    5. 精確怕匹配前一列後一列進行範圍查找: 比如 age = 18 and create_time >= 2012-05-25 21:18:12 and create_time <= 2019-05-25 21:18:12 ,索引的前一列準確查詢後一列範圍查詢。
    6. 只訪問索引查詢:select age / select age , create_time from example_table where ....,查詢字段即使索引,在後續的優化中會對,只查詢索引,避免查詢數據行的情況 "覆蓋索引”;
    7. 如果不是按照索引的最左前綴查找無法使用索引,因爲索引的排序規則根據創建表語句中索引的定義順序來排序。
    8. 不能跳過列進行查詢,即index(a,b,c),如果查詢a = ? and c = ?只能用到第一列索引(a);
    9. 如果查詢中,某個列進行範圍查詢,後面的列都不能使用索引查詢。

Hash索引:(Key-Value)

  1. 通過哈希函數計算hash值在對應的槽位存放指向對應行數據的指針。 
  2. 哈希索引只保存哈希值和行指針,而不存放字段值,所以不能使用索引中的值來避免讀取行。
  3. 哈希索引數據不是根據索引值順序存儲的,所以無法排序。
  4. 哈希索引也不支持部分索引列匹配,因爲哈希值是根據所有哈希內容來計算哈希值的。
  5. 哈希索引只支持等值比較查詢,包括=,IN(),<=>,不支持任何的範圍查詢。
  6. 訪問哈希索引的數據非常快O(1),但是如果哈希衝突嚴重的話,必須遍歷鏈表來查找對應的數據,代價非常大。

全文索引&空間數據索引:可以自己探索下,全文索引多用於搜索引擎(Solr等)

索引優點總結:

  1.  索引的列可以保證行的唯一性,生成唯一的rowId

  2. 索引大大減少了服務器需要掃描的數據量,可以有效縮短數據的檢索時間

  3. 索引可以幫助服務器避免排序和臨時表

  4. 索引可以將隨機I/O改成順序I/O

索引缺點總結:

  1. 創建索引和維護索引需要時間成本,這個成本隨着數據量的增加而加大

  2. 創建索引和維護索引需要空間成本,每一條索引都要佔據數據庫的物理存儲空間,數據量越大,佔用空間也越大(數據表佔據的是數據庫的數據空間)

  3. 會降低表的增刪改的效率,因爲每次增刪改索引需要進行動態維護,導致時間變長。

聚簇索引,非聚簇索引的區別?底層實現原理以及兩者的優缺

       聚簇索引是對磁盤上實際數據重新組織以按指定的一個或多個列的值排序的算法。特點是存儲數據的順序和索引順序一致。
一般情況下主鍵會默認創建聚簇索引,且一張表只允許存在一個聚簇索引。

      聚簇索引的葉子節點就是數據節點,而非聚簇索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。

      MYISAM是按列值與行號來組織索引的。它的葉子節點中保存的實際上是指向存放數據的物理塊的指針。
從MYISAM存儲的物理文件我們能看出,MYISAM引擎的索引文件(.MYI)和數據文件(.MYD)是相互獨立的。而InnoDB按聚簇索引的形式存儲數據,所以它的數據佈局有着很大的不同

     INNODB的二級索引與主鍵索引有很大的不同。InnoDB的二級索引的葉子包含主鍵值,而不是行指針(row pointers),這減小了移動數據或者數據頁面分裂時維護二級索引的開銷,因爲InnoDB不需要更新索引的行指針。

    INNODB和MYISAM的主鍵索引與二級索引的對比:

    InnoDB的的二級索引的葉子節點存放的是KEY字段加主鍵值。因此,通過二級索引查詢首先查到是主鍵值,然後InnoDB再根據查到的主鍵值通過主鍵索引找到相應的數據塊。而MyISAM的二級索引葉子節點存放的還是列值與行號的組合,葉子節點中保存的是數據的物理地址。所以可以看出MYISAM的主鍵索引和二級索引沒有任何區別,主鍵索引僅僅只是一個叫做PRIMARY的唯一ID.

設計表規約以及提高性能策略(SQL優化)_中型數據表

  1.  數據庫設計方面
    1. 建表約束
      1. 必須有字段id(主鍵id,一般設置爲自增(步數爲1),當併發性需求較高的時候,不建議自增,可以自定義實現機制), create_time(建表時間), update_time(更新時間,設置爲自動更新)。
      2. 表名和字段名必須使用小寫字母或數字,禁止數字開頭,同時使用下劃線分割不同的單詞,Windows環境下Mysql忽略大小寫,Linux下大小寫是有區分的,因此爲了統一,全部是小寫字母加數字,同時命名不能用複數名詞,表明和字段名應用來表示含義。
      3. 表示有是否含義的字段時,必須用is_XXX來表示字段名,用tinyint unsigned(1是, 0否),當然也可以使用char(1)來表示'Y'(是), 'N'(否)。
      4. 同時禁止使用MySql保留字段,desc,range等,用過的同學應該知道這個會報錯。
      5. 主鍵的索引名必須爲pk_xxx,唯一索引名爲uk_xxx,普通索引名爲idx_xxx。
      6. 對於數字類型的定義比如bigint(1)與bigint(5)的原理和佔用空間都是一樣的,不同的長度是不同工具對數字的表形式不同,兩者沒有任何差別。
      7. 小數類型用decimal來儲蓄,儘量根據單位換算用Bigint unsigned等整形來表示,因爲MySql小數的運算相比整數消耗資源會更多一點。
      8. char用來表示定長字符,varchar用來儲蓄可變字符,根據需求進行字段長度的設置,可以多餘,但要適量。
      9. 對於業務上不發生改變的字段設爲枚舉,在MySql中枚舉的儲蓄也更加的緊湊,查詢的效率也更好點。
      10. 對於需要用有限數字來表示字段信息時,不要用‘0’來表示某種狀態,某些情況下JAVA中部分字段的默認值爲‘0’,可能會發生一些不必要的錯誤。
    2. 索引約束
      1. 業務上唯一的字段,索引必須爲唯一索引。比如user_id(假設每個用戶只有一個id,若此字段需要建立索引,必須使用唯一索引。
      2. 在varchar字段上建立索引時,索引長度必須指定,根據業務情況的區分度來設置,一半20的區分度爲90%。
      3. 建立組合索引時,區分度高的在左邊。
      4. 同時,索引的數量單表至多6個,因爲索引的維護(頻繁的刪除和插入操作),會帶來比較高的資源消耗,因此不要在頻繁刪除和更新的字段加索引。
    3. 案列表
      1. CREATE TABLE `product` (
        	`id` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID',
        	`uuid` CHAR ( 32 ) NOT NULL COMMENT '產品UUID',
        	`user_uuid` CHAR ( 32 ) NOT NULL COMMENT '用戶UUID',
        	`pack_amount` SMALLINT ( 6 ) NOT NULL COMMENT '打包價格\r\n',
        	`term` INT ( 10 ) UNSIGNED NOT NULL COMMENT '借款限期,單位-天',
        	`remark` VARCHAR ( 5 ) DEFAULT '' COMMENT '備註',
        	`product_type` TINYINT ( 4 ) NOT NULL COMMENT '產品類型(1:賺,2:借款,3:轉售)',
        	`status` TINYINT ( 4 ) UNSIGNED NOT NULL COMMENT '產品狀態',
        	`expend_rate` DECIMAL ( 16, 2 ) NOT NULL COMMENT '利率',
        	`effective_time` datetime NOT NULL COMMENT '標的發佈的有效期(時間戳)',
        	`create_time` datetime NOT NULL COMMENT '創建時間',
        	`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
        	PRIMARY KEY ( `id` ),
        	UNIQUE KEY `idx_uuid` ( `uuid` ),
        	KEY `idx_user_uuid` ( `user_uuid` ),
                KEY `idx_create_time` ( `create_time` ) 
        ) ENGINE = INNODB AUTO_INCREMENT = 2 DEFAULT CHARSET = utf8 COMMENT = '產品基礎信息表';

         

    4. 字段的選取(最小原則)
      1. 越小的數據類型,通常處理的速度更快,因爲佔用的磁盤,內存,CPU緩存更少,處理時需要的CPU週期也更短。對於不確定的數值範圍,選取最小的可儲蓄類型。
    5. 數據類型 數值範圍 字節 常用場景
      tinyint unsigned 0-255 1 表示人的年齡等
      smallint unsigned 0-65535 2 烏龜年齡等
      int unsigned 0-42.9億 4 恐龍化石時間等
      bigint unsigned 0-10^19 8 太陽的年齡
      char(N) 最大爲N個字節 N 對於固定長度的字段(比如人名)
      varchar(N) 最大爲N個字節,N儘量小於255/5000 N 根據業務需求
      datatime 1601-9999年 8 常用的日期儲蓄
      timestamp 1601-9999年 4 有自動更新機制,update_time
    6. 簡單原則
      1. 簡單的數據類型需要的CPU週期更短,整形比字符整體的操作代價少很多,建議IP的儲蓄用整型。
    7. 儘量避免使用NULL
      1. 通常情況下,字段設置爲NOT NULL,NULL爲默認屬性,對於查詢來說有NULL的列,MySql優化很難,查詢起來會更麻煩,佔用的儲蓄空間可更多
  2. SQL查詢優化
    1. 查詢優化,在where以及order by 涉及的字段上建立索引。
    2. 避免使用where 屬性 = null,這樣MySQL會進行全局查詢。
    3. 避免在where使用 != 或 < > 等字段。
    4. 避免where 與 or 進行連接查詢,使用 union all 進行代替.
    5. 避免使用 in 和 not in 等,連續的範圍儘量用between
    6. 避免使用like "%XX%".
    7. 避免where 的字段使用表達式操作.where num/2 = x等
    8. 避免where的字段使用函數操作。
    9. 字段含有大量的相同值比如(sex..),索引的優化沒有效果,,MySQL根據字段的內容進行優化,因此進行建立索引;
    10. 索引提高的select 的效率,但降低了insert ,update的效率,建議索引最多建立6個.
    11. 字段的內容如果都爲數字的話,避免使用字符作爲屬性,字符根據每個字符進行比較,數字只會比較一次;
    12. select * from table,儘量使用字段代替 * ,減少查詢量,即使需要查詢字段也要用全部字段代替 *。
    13. 維護索引的代價比較高,主鍵索引儘量使用自增形式(數據庫自增/業務實現自增ID),避免不必要的索引頁調整。。 
  3. 數據庫版本,服務器內存與性能對比(X軸表示內存容量GB,Y軸每秒查詢次數

爲什麼選擇B+樹而不是 二叉排序樹,Hash,B樹,查找樹,AVL樹,優缺點是什麼呢?

  1. 二叉排序樹:根節點大於左邊小於右邊,極端情況下,比如有序的插入,就會出現退化的現象,二叉排序樹退化成鏈表,因此推出平衡樹。
  2. AVL,紅黑樹:保證了樹的平衡性,查詢性能穩定提高,但是因爲都是單節點,數據量大的時候,樹的高度會非常高,查詢效率會減少,因此提出多路查詢。
  3. B樹:多路搜索樹,他每個節點可以擁有多餘兩個孩子節點,M路的B樹最多有M個子節點,此時樹的高度降低,查詢效率同時提高,如果無線多路則退化成有序數組,因其子節點是索引,對於範圍查詢時需要部分中序遍歷來完成,效果不好。
  4. Hash:  其優缺點可以查看Hash索引類型的介紹。       
  5. 聚簇索引的優缺點:
    1. 優點:
      1. B+-tree的查詢效率更加穩定  由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。                                                                                                                    
      2. B+-tree的磁盤讀寫代價更低  B+-tree的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。  舉個例子,假設磁盤中的一個盤塊容納16bytes,而一個關鍵字2bytes,一個關鍵字具體信息指針2bytes。一棵9階B-tree(一個結點最多8個關鍵字)的內部結點需要2個盤快。而B+ 樹內部結點只需要1個盤快。當需要把內部結點讀入內存中的時候,B 樹就比B+ 樹多一次盤塊查找時間(在磁盤中就是盤片旋轉的時間)。
      3. 自適應Hash,InnoDB會對經常訪問的索引創建哈希表,加快訪問速度。
    2. 缺點:
      1. 聚簇索引提高了IO密集型應用的性能,但如果數據都放在內存中,訪問的順序就不再重要,聚簇索引也沒有優勢。
      2. 插入速度依賴於插入的順序。按照逐漸順序插入是加載數據到InnoDB表中速度最快的方式,因爲主鍵的值是順序的,InnoDB把每一條疾苦都存儲在一條記錄的後面,當達到頁的填充因子時(15/16),下一條記錄就會寫入新的頁中。
      3. 如果使用UUID,InnoDB無法簡單的將新行插入到索引的最後,而是爲新行尋找合適的位置,通常在已有數據的中間位置。
        1. 寫入的目標頁可能已經刷新到磁盤上,並且從緩存中移除,或者沒有被加載進緩存中,InnoDB不得從磁盤將頁導入內存,導致大量的隨機IO。
        2. 寫入是亂序的,InnoDB不得不頻繁的做頁分裂操作,以便爲新的行分配空間,頁分裂導致大量的數據移動。
      4. 二級索引可能比想象的大,因爲二級索引葉子節點包含引用的主鍵列。

文獻:

發佈了18 篇原創文章 · 獲贊 24 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章