13-6_mysql索引_1_Mysql_Learning_Notes_20180719_13-6

mysql索引_1_Mysql_Learning_Notes

一種在有序數組中查找某一特定元素的搜索算法;
二分查找法的優勢是比較少次數,查找速度快,平均性能好;其缺點是要求待查表爲有序表,且插入刪除困難,所以二分查找方法適用於不常常變更而查找頻繁的有序列表.node

  • innodb 要求彙集索引列都要求是有序自增列.innnodb 是事務型的存儲引擎,其中的行老是會被刪除並提交,count(*) 相對要慢一些.mysql

    二叉樹,binary tree

  • 二叉樹的每一個節點至多隻有二棵子樹(不存在大於2的節點),二叉樹的子樹有左右有序之分,次序不能顛倒.左子樹必定小於根,右子樹必定大於根.根節點是子節點的中間節點.算法

4
  1               10

平衡樹,平衡二叉樹,Self balancing binary search tree

  • 改進的二叉查找樹.通常的二叉查找樹的查詢複雜度是跟目標節點到樹根的距離(深度)有關,所以當前節點的深度廣泛較大時,查詢的均攤複雜度會上升.爲了更高效的查詢就有了平衡樹.
  • 平衡二叉樹的特色:
    • 它是一棵空樹或其左右兩個子樹的高度差的絕對值不超過1(好比左邊高度是6,右的高度只能是5或7),且左右兩個子樹也是平衡二叉樹.
    • 不平衡的樹會經過自旋變成平衡樹.
    • 平衡樹和二叉查找樹最大的區別是:前者是平衡的,後者不必定.
    • 數據庫裏使用平衡二叉樹,若是有插入值很大可能會致使其自旋?.
      Alt textsql

      B樹,balanced tree(平衡多叉樹)

  • 又稱B-樹\B_樹
  • B樹,一個節點能夠擁有多於2個的子節點的多叉查找樹
  • 適合大量數據的讀寫操做,廣泛運用在數據庫和文件系統.
  • 一棵m階(好比m=4階)的B樹知足如下條件.
    • 樹中每一個節點至多有m個(4個)子節點
    • 除根節點和葉子節點外,其它每一個節點至少有m/2個(2個)子節點.
    • 若根節點不是葉子節點,則至少有2個子節點.
    • 全部葉子節點都出如今同一層,葉子節點不包含任何鍵值信息.
    • 有k個子節點的非葉子節點剛好包含有k-1個鍵值(索引節點)數據庫

      記錄中應該用'節點'仍是'結節',baidu了一下,有師兄解釋:一個節點是兩線相交,中間的點,另外一個結點是最後的點。二叉樹好像特別一點,是結點,葉子結點和非葉子節點(但不肯定正確性,我就全部都用節點了)數組

      B+樹,與B樹不一樣點在:

  • 有n棵子樹對的節點(node)中含有n-1個關鍵字(key),每一個關鍵字不保存數據,只用來索引,全部數據都保存在葉子節點.
  • 全部的葉子節點中包含了所有關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子節點自己依關鍵字的大小自小而大順序連接.
  • 全部的非葉子節點能夠當作是索引的部分,節點中僅含其子樹(根節點)中的最大(或最小)關鍵字.
  • 在MySQL中,爲了方便,直接寫成BTREEbash

    B+樹高度相關性

    高度
    1
    2
    3
    4
  • 以三層B+樹爲列,最查詢3次,平均不到3次就能夠查詢到結果.查詢效率高,XFS文件系統也是使用的B+樹,因此優於以前的esx4
  • 怎麼看innodb的B+TREE層數?,下面以sysbench_testdata.sbtest2爲例查看索引層數:
    • 查看相關係統
      ``sql root@localhost [sysbench_testdata]>show create table sbtest2; | sbtest2 | CREATE TABLEsbtest2(idint(11) NOT NULL AUTO_INCREMENT,kint(11) NOT NULL DEFAULT '0',cchar(120) NOT NULL DEFAULT '',padchar(60) NOT NULL DEFAULT '', PRIMARY KEY (id), KEYk_2(k`)
      ) ENGINE=InnoDB AUTO_INCREMENT=67840915 DEFAULT CHARSET=utf8 |
      1 row in set (0.00 sec)

root@localhost [sysbench_testdata]>select count(id) from sbtest2;
+-----------+
| count(id) |
+-----------+
| 67840914 |
+-----------+
1 row in set (56.87 sec)數據結構

```性能

  • 查看information_schema中相關表信息,注意索引的PAGE_NO和:index_id
root@localhost [sysbench_testdata]>SELECT b.name, a.name, index_id, type, a.space, a.PAGE_NO FROM information_schema.INNODB_SYS_INDEXES a, information_schema.INNODB_SYS_TABLES b WHERE a.table_id = b.table_id AND a.space <> 0 and b.name='sysbench_testdata/sbtest2';
+---------------------------+---------+----------+------+-------+---------+
| name                      | name    | index_id | type | space | PAGE_NO |
+---------------------------+---------+----------+------+-------+---------+
| sysbench_testdata/sbtest2 | PRIMARY |       51 |    3 |    33 |       3 |
| sysbench_testdata/sbtest2 | k_2     |       58 |    0 |    33 |      38 |
+---------------------------+---------+----------+------+-------+---------+
2 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>show global variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.00 sec)
  • 到表的文件系統目錄中:cd /data/57mysql/mysql3508/data/sysbench_testdata
#hexdump -s 49216 -n 10 ./sbtest2.ibd
000c040 0300 0000 0000 0000 3300               
000c04a

#hexdump -s 622656 -n 10 ./sbtest2.ibd
0098040 0200 0000 0000 0000 3a00               
009804a
  • 注:hexdump中49216和622656是怎麼算出來的?這個數分別對應sbtest2表的兩個索引,公式是 page_no * innodb_page_size + 64。PRIMARY:316384+64=49216 k_2:3816384+64=622656 ,同時能夠觀察hexdump結果中的3300和3a00,此數十六進制爲33和3a,轉換成十進制爲:51和58,分別和information_schema中的index_id對應上了.
  • 能夠發現 主鍵索引(PRIMARY)的PAGE_LEVEL 爲 0300,表示這棵二級索引樹的高度爲 4,k_2索引的PAGE_LEVEL 爲 0200,表示這棵二級索引樹的高度爲 3.

哈希索引,Hash Index

  • 創建在哈希表的基礎上,它只對使用了索引中的每一個值的精確查找有用.
  • 對於每一行,存儲引擎計算出了被索引的哈希碼(Hash Code),它是一個較小的值,而且有可能和其餘行的哈希碼不一樣(對象相等則hashCode必定相等;hashCode相等對象未必相等)
  • 把哈希碼保存在索引中,而且保存了一個指向哈希表中的每一行的指針
  • 也叫散列索引.
  • 問題:若是不一樣對像產生了相同的hashCode(哈希衝突),如在索引表裏沒法作到一一對應到記錄行?
  • 哈希索引優點:合適大量的等值查詢,此種狀況效率高於B+TREE
  • HASH Index 缺點:
    • 不支持模糊查詢和範圍查詢
    • 不支持排序
    • 不支持聯合索引中的最左匹配規則
    • 只能顯式應用於HEAP/MEMORY/NDB表
  • 注意:Innodb內部的自適應哈希索引和此處說的不是一回事.自適應哈希索引是沒辦法被引用和修改的,innodb自適應哈希索引只能用啓用或禁用,沒辦法指定某一個表使用哈希索引.

什麼是索引

至關於書目,用於快速檢索mysql索引

  • 優勢
    • 提升數據檢索效率
    • 提升表間的join效率
    • 利用惟一性索引,保證數據的惟一性.
    • 提交排序和分組效率.
  • 缺點
    • 消耗更多物理存儲空間
    • 數據變動時,索引也須要更新,下降更新效率.(更新索引時會致使cpu在sys增高),在5.7以上,能夠經過查詢獲得索引的利用率.

      MySQL 5.7之後怎麼查看索引使用狀況?
  1. 經過show status like '%Handler_read%'方法查看:總體的
root@localhost [sysbench_testdata]>show status like '%Handler_read%';
+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Handler_read_first    | 7       |
| Handler_read_key      | 29      |
| Handler_read_last     | 0       |
| Handler_read_next     | 8446377 |
| Handler_read_prev     | 0       |
| Handler_read_rnd      | 20      |
| Handler_read_rnd_next | 8344612 |
+-----------------------+---------+
7 rows in set (0.00 sec)
  • Handler_read_key這個值表明了一個行將索引值讀的次數,很低的值代表增長索引獲得的性能改善不高,由於索引並不常用。

  • Handler_read_rnd_next 的值高則查詢低效,而且應該創建索引補救。這個值是指在數據文件中讀下一行的請求數。若是正進行大量的表掃描,Handler_read_rnd_next的值較高,則一般說明表索引不正確或查詢沒有利用索引

2.查看具體某一個sql的索引使用狀況 :

root@localhost [sysbench_testdata]>explain select k from sbtest2 where k=432 limit 2;
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
|  1 | SIMPLE      | sbtest2 | NULL       | ref  | k_2           | k_2  | 4       | const | 110944 |   100.00 | Using index |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

字段說明:
Type:告訴咱們對錶所使用的訪問方式,主要包含以下集中類型;
◇ all:全表掃描
◇ const:讀常量,且最多隻會有一條記錄匹配,因爲是常量,因此實際上只須要讀一次;
◇ eq_ref:最多隻會有一條匹配結果,通常是經過主鍵或者惟一鍵索引來訪問;
◇ fulltext:
◇ index:全索引掃描;
◇ index_merge:查詢中同時使用兩個(或更多)索引,而後對索引結果進行merge 以後再讀取表數據;
◇ index_subquery:子查詢中的返回結果字段組合是一個索引(或索引組合),但不是一個主鍵或者惟一索引;
◇ rang:索引範圍掃描;
◇ ref:Join 語句中被驅動表索引引用查詢;
◇ ref_or_null:與ref 的惟一區別就是在使用索引引用查詢以外再增長一個空值的查詢;
◇ system:系統表,表中只有一行數據;
◇ unique_subquery:子查詢中的返回結果字段組合是主鍵或者惟一約束;

possible_keys:可能能夠利用的索引的名字。這裏的索引名字是建立索引時指定的索引暱稱;若是索引沒有暱稱,則默認顯示的是索引中第一個列的名字(在本例中,它是「firstname」)。默認索引名字的含義每每不是很明顯。  

key:它顯示了MySQL實際使用的索引的名字。若是它爲空(或NULL),則MySQL不使用索引。  

key_len:索引中被使用部分的長度,以字節計

ref:列出是經過常量(const),仍是某個表的某個字段(若是是join)來過濾(經過key)
的;

rows:MySQL所認爲的它在找到正確的結果以前必須掃描的記錄數。顯然,這裏最理想的數字就是1。

  1. 經過performance_schema能夠查詢到.查看sbtest2表索引狀況的查詢語句:
root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
  • 具體查看過程:
root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    1697669
Current database: sysbench_testdata

+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          0 |          0 |           0 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287298 |   76287298 |    76287298 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>select k from sbtest2 where k=432 limit 2;                                                                                                       
+-----+
| k   |
+-----+
| 432 |
| 432 |
+-----+
2 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          0 |          0 |           0 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287300 |   76287300 |    76287300 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.01 sec)

root@localhost [sysbench_testdata]>select k from sbtest2 where id=432 limit 2;                                                                                                               
+-------+
| k     |
+-------+
| 49866 |
+-------+
1 row in set (0.00 sec)

root@localhost [sysbench_testdata]>select object_type,object_schema,object_name,index_name,count_star,count_read,COUNT_FETCH from performance_schema.table_io_waits_summary_by_index_usage where object_name='sbtest2';
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| object_type | object_schema     | object_name | index_name | count_star | count_read | COUNT_FETCH |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
| TABLE       | sysbench_testdata | sbtest2     | PRIMARY    |          1 |          1 |           1 |
| TABLE       | sysbench_testdata | sbtest2     | k_2        |   76287300 |   76287300 |    76287300 |
| TABLE       | sysbench_testdata | sbtest2     | NULL       |    8344631 |    8344631 |     8344631 |
+-------------+-------------------+-------------+------------+------------+------------+-------------+
3 rows in set (0.00 sec)

root@localhost [sysbench_testdata]>

索引使用建議

  • 哪一種狀況下應該建立索引
    • 常常檢索的列
    • 常常用於錶鏈接的列
    • 常常排序或分組的列
  • 不建議使用索引的狀況
    • 基數很低的列
    • 更新頻繁但檢索不頻繁的列
    • BLOB/TEXT等長內容列
    • 不多用於檢索的列

彙集索引,clustered index

  • 彙集索引是一種索引,該索引中鍵值的邏輯順序決定了表數據行的物理順序(注:在彙集索引下,數據在物理上按順序排在數據頁上,重複值也排在一塊兒,於是在那些包含範圍檢查(between、<、<=、>、>=)或使用group by或orderby的查詢時,一旦找到具備範圍中第一個鍵值的行,具備後續索引值的行保證物理上毗連在一塊兒而沒必要進一步搜索,避免了大範圍掃描,能夠大大提升查詢速度)
  • 每張表只能建一個彙集索引,除了TokuDB引擎
  • InnoDB中,彙集索引即表,表即彙集索引(注:mysql一個表只支持一個彙集索引。在innodb裏面彙集索引就是整個表,表就是彙集索引,由於innodb的彙集索引後面是整行數據,若是主鍵由多列組成,btree優先按第一列順序存儲,在彙集索引btree裏面每一個葉子節點最終存儲每行數據,這就是爲何在innodb裏面沒有任何條件count (*),它會優先選擇普通索引來完成掃描,而不是採用主鍵索引,由於若是掃彙集索引,掃描的數據量更大,產生的IO更大,若是掃描普通輔助索引,那麼它的數據結構一般來說比主鍵索引小。)
  • MyISAM 沒有彙集索引的概念.
  • InnoDB表中主鍵必定是彙集索引,但彙集索引不必定是主鍵.
  • 在彙集索引中不要包含常常修改的列,由於碼值修改後,數據行必須移動到新的位置。同時新增數據過於離散隨機也不合適.
  • INT/BIGINT(單調順序列)可優先作爲彙集索引
  • mysql 彙集索引的選擇順序:若是有主鍵則選擇主鍵,沒有主鍵則選擇第一個not nullable的惟一索引,沒有知足要求的惟一鍵,最後會使用rowid.,但這個rowid爲實例級全局id,因此若是彙集索引若是選擇rowid,可能會致使性能下降

    主鍵索引(PRIMARY KEY)

  • 主鍵由表中的一個或多個字段組成,它的值用於惟一的標識表中的某一條記錄;
  • 在表引用中,主鍵在一個表中引用來自另外一個表中的特定記錄(外鍵foreign key應用);
  • 保證數據的完整性
  • 加快數據的操做速度;
  • 主鍵值不能重複,也不能包含null.
  • 主鍵選擇建議:
    • 對業務透明,無心義,免受業務變化影響.
    • 不多修改和刪除
    • 最好是自增的
    • 不要具備動態屬性(如隨機值)
  • MySQL 5.6.9及之後無論索引定義時,有無顯示包含主鍵,實際都會存儲主鍵值,如:c1爲主鍵,索引z,爲c2,c3聯合索引,但z會存儲c1的值,這一特性加:索引擴展(Index Extensions).
    -查詢中是基於主鍵好,仍是惟一索引好?

    惟一索引(UNIQUE KEY)

  • 不容許具備索引值相同的行,從而禁止重複的索引或鍵值;
  • 嚴格意義上講,應該叫惟一約束;
  • 在惟一約束上和主鍵同樣(以MyISAM引擎爲表明)
  • 惟一索引容許有空值(null)
  • 一個表只能有一個主鍵,但能夠有多個惟一索引;
  • 惟一索引約束可臨時禁用,但主鍵不行;

    聯合索引(Combined Indexes,Multiple-Column Indexes)

  • 多列組成,因此也叫多列索引
  • 字段從左到右排序,如c1,c2,c3的聯合索引,首先進行c1排序,c1字段值相同的按c2排序,若是前兩列都相同纔會按c3排序.
    |c1|c2|c3|
    |-|
    |1|2|2|
    |2|3|2|
    |2|4|2|
    |3|2|0|
    |3|2|2|
  • 適合where條件中的多列組合
  • 有時候,還能夠用於避免回表(覆蓋索引,須要的數據都在索引覆蓋的字段範圍內,不須要再去表中取數據,若是使用的覆蓋索引,執行計劃中的Extra列會顯示關鍵字:using index)
  • MySQL還不支持多列不一樣排序規則(8.0起支持)
  • 建議:1.where條件中,常常同時出現的列放在聯合索引中;2把選擇性(過濾性/基數)大的列放在聯合索引的最左邊(常常出現的列放在最左邊).

    覆蓋索引(covering indexes)

  • 經過索引數據結構,便可直接返回數據,不須要回表;
  • 執行計劃中的Extra列會顯示關鍵字:using index.

相關文章
相關標籤/搜索