MYSQL索引-一百萬條數據進行測試


前言:

  測試在mysql中使用索引和不使用索引查詢數據的速度區別、

創建測試用表:

CREATE TABLE `app_user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT '', `email` varchar(50) NOT NULL, `phone` varchar(20) DEFAULT '', `gender` tinyint(4) unsigned DEFAULT '0', `password` varchar(100) NOT NULL DEFAULT '', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8

向表中插入一百萬條數據:

 

-- 1、插入100萬數據.
DELIMITER $$
-- 寫函數之前必須要寫$$標志
CREATE FUNCTION mock_data () RETURNS INT BEGIN DECLARE num INT DEFAULT 1000000; DECLARE i INT DEFAULT 0; WHILE i<num DO INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`)VALUES(CONCAT('用戶',i),'19224305@qq.com','123456789',FLOOR(RAND()*2)); SET i=i+1; END WHILE; RETURN i; END; -- 2、執行此函數 生成一百萬條數據大約要執行半分鍾 SELECT mock_data() -- 3、查詢表中數據 select * from app_user;

查詢數據:

可以看到查詢用戶名為“用戶名888888”的信息,耗費了0.5s左右,在人的眼睛中這是非常短暫的,但是在計算機的世界中,是非常久的。所以我們要做一些優化

添加索引:

ALTER TABLE app_user add INDEX app_user_index(`name`);

添加索引后我們再來測試下查詢數據需要多久:

 

 

 

 

 

 索引的實現原理:

BTree索引和B+Tree索引

 

  • BTree索引

BTree是平衡搜索多叉樹,設樹的度為2d(d>1),高度為h,那么BTree要滿足以一下條件:

  • 每個葉子結點的高度一樣,等於h;
  • 每個非葉子結點由n-1個key和n個指針point組成,其中d<=n<=2d,key和point相互間隔,結點兩端一定是key;
  • 葉子結點指針都為null;
  • 非葉子結點的key都是[key,data]二元組,其中key表示作為索引的鍵,data為鍵值所在行的數據;

BTree的結構如下:

在BTree的機構下,就可以使用二分查找的查找方式,查找復雜度為h*log(n),一般來說樹的高度是很小的,一般為3左右,因此BTree是一個非常高效的查找結構。

BTree的查詢、插入、刪除過程可以參考:https://blog.csdn.net/endlu/article/details/51720299

  • B+Tree索引

B+Tree是BTree的一個變種,設d為樹的度數,h為樹的高度,B+Tree和BTree的不同主要在於:

  • B+Tree中的非葉子結點不存儲數據,只存儲鍵值;
  • B+Tree的葉子結點沒有指針,所有鍵值都會出現在葉子結點上,且key存儲的鍵值對應data數據的物理地址;
  • B+Tree的每個非葉子節點由n個鍵值key和n個指針point組成;

B+Tree的結構如下:

B+Tree對比BTree的優點:

1、磁盤讀寫代價更低

一般來說B+Tree比BTree更適合實現外存的索引結構,因為存儲引擎的設計專家巧妙的利用了外存(磁盤)的存儲結構,即磁盤的最小存儲單位是扇區(sector),而操作系統的塊(block)通常是整數倍的sector,操作系統以頁(page)為單位管理內存,一頁(page)通常默認為4K,數據庫的頁通常設置為操作系統頁的整數倍,因此索引結構的節點被設計為一個頁的大小,然后利用外存的“預讀取”原則,每次讀取的時候,把整個節點的數據讀取到內存中,然后在內存中查找,已知內存的讀取速度是外存讀取I/O速度的幾百倍,那么提升查找速度的關鍵就在於盡可能少的磁盤I/O,那么可以知道,每個節點中的key個數越多,那么樹的高度越小,需要I/O的次數越少,因此一般來說B+Tree比BTree更快,因為B+Tree的非葉節點中不存儲data,就可以存儲更多的key。

2、查詢速度更穩定

由於B+Tree非葉子節點不存儲數據(data),因此所有的數據都要查詢至葉子節點,而葉子節點的高度都是相同的,因此所有數據的查詢速度都是一樣的。

索引的使用場景:

什么時候要使用索引?

  • 主鍵自動建立唯一索引;
  • 經常作為查詢條件在WHERE或者ORDER BY 語句中出現的列要建立索引;
  • 作為排序的列要建立索引;
  • 查詢中與其他表關聯的字段,外鍵關系建立索引
  • 高並發條件下傾向組合索引;
  • 用於聚合函數的列可以建立索引,例如使用了max(column_1)或者count(column_1)時的column_1就需要建立索引

什么時候不要使用索引?

  • 經常增刪改的列不要建立索引;
  • 有大量重復的列不建立索引;
  • 表記錄太少不要建立索引。只有當數據庫里已經有了足夠多的測試數據時,它的性能測試結果才有實際參考價值。如果在測試數據庫里只有幾百條數據記錄,它們往往在執行完第一條查詢命令之后就被全部加載到內存里,這將使后續的查詢命令都執行得非常快--不管有沒有使用索引。只有當數據庫里的記錄超過了1000條、數據總量也超過了MySQL服務器上的內存總量時,數據庫的性能測試結果才有意義。

索引失效的情況:

  • 在組合索引中不能有列的值為NULL,如果有,那么這一列對組合索引就是無效的。
  • 在一個SELECT語句中,索引只能使用一次,如果在WHERE中使用了,那么在ORDER BY中就不要用了。
  • LIKE操作中,'%aaa%'不會使用索引,也就是索引會失效,但是‘aaa%’可以使用索引。
  • 在索引的列上使用表達式或者函數會使索引失效,例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成:select * from users where adddate<’2007-01-01′。其它通配符同樣,也就是說,在查詢條件中使用正則表達式時,只有在搜索模板的第一個字符不是通配符的情況下才能使用索引。
  • 在查詢條件中使用不等於,包括<符號、>符號和!=會導致索引失效。特別的是如果對主鍵索引使用!=則不會使索引失效,如果對主鍵索引或者整數類型的索引使用<符號或者>符號不會使索引失效。(,不等於,包括&lt;符號、>符號和!,如果占總記錄的比例很小的話,也不會失效)
  • 在查詢條件中使用IS NULL或者IS NOT NULL會導致索引失效。
  • 字符串不加單引號會導致索引失效。更准確的說是類型不一致會導致失效,比如字段email是字符串類型的,使用WHERE email=99999 則會導致失敗,應該改為WHERE email='99999'。
  • 在查詢條件中使用OR連接多個條件會導致索引失效,除非OR鏈接的每個條件都加上索引,這時應該改為兩次查詢,然后用UNION ALL連接起來。
  • 如果排序的字段使用了索引,那么select的字段也要是索引字段,否則索引失效。特別的是如果排序的是主鍵索引則select * 也不會導致索引失效。
  • 盡量不要包括多列排序,如果一定要,最好為這隊列構建組合索引;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM