一次mysql大数据量查询 慢查询导致服务阻塞后的学习
場景還原:前一個月給朋友寫了個簡單的登錄功能,簡單的查詢數據庫登錄邏輯,使用mysbatis-plus進行的dao層代碼生成(吐槽一下這個工具,真是方便一時爽,后面維護難,比較喜歡自己能夠組裝和優化sql,大數據量插入時候mybatis-plus性能極差都是生成的單條插入sql然后flush),沒想到啊,哥們的應用流量這么,數據量這么多。。很多問題都是這樣,在小數據量,低頻訪問時候都是正常的,一旦有了流量很多問題就都出現了。用戶點擊登錄按鈕后,服務端長時間未響應。聽到朋友描述后,我背后一涼,猜到可能是mysql出問題了,用的都是我自己搭建的,單臺的mysql
查了一下資源使用情況
看完心涼了。。。mysql沒加任何索引,都是全表查詢,當時緊急處理,把所有用戶登錄數據導入redis(百萬級的數據量,且密碼是服務端生成,用戶無法修改),暫時抗住了壓力(之后回查了一下當時的流量??Max QPS 870左右)
通過這個應該可以算上事故的問題,下定決心要學習一下mysql的索引創建以及使用場景應用
學習過程:首先先創建一張測試表
CREATE TABLE `user` (
? `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
? `user_name` varchar(32) NOT NULL DEFAULT '',
? `nick_name` varchar(32) NOT NULL,
? `pass_word` varchar(32) NOT NULL DEFAULT '',
? `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
? PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
寫一個生成1000萬條數據的存儲過程:
DELIMITER //
create procedure test_proc() ?
begin ?
? ?declare num int DEFAULT 1; ??
? ?while num <= 10000000 do ?
? ?insert into user(user_name,nick_name,pass_word) values(num,'保密',PASSWORD(num)); ?
? ?set num=num+1;?
? ?end while;?
?end?
?//
DELIMITER ;
執行存儲過程:(要等幾分鐘,如果覺得慢可以寫一些拼接sql批插入)
call test_proc();
測試一下查詢時間
select user_name,pass_word from user where user_name = '100000' or ?pass_word = '*8AB26805E964C278E555D5DA0C9F0D8';
MyISAM 查詢需要1.53s
換一下InnoDB試一下 2.85s (MyISAM一般作為查詢庫,InnoDB有事務一般用在寫比較的庫)
查看一下當前表的索引情況的sql : show index from user;
這篇博客先使用一下最常用的普通索引進行一下優化:
?alter table user add index index_user_name(user_name);
創建了一個簡單索引之后的查詢結果如下:
下面介紹一下可能會踩到的索引失效的坑:
1、如果是varchar類型沒有加`` 符號還是會進行全表掃描
2、sql語句上盡可能不要用like,在索引字段上使用like還是會進行全表掃描
3、使用is null 或 is not null
4、使用函數作為where查詢的條件
5、使用不等于操作符(<> ,!=,not in,in)
只是簡單的加一下索引在user_name上就能優化這么明顯,那是不是索引就能隨便添加了呢?
1、如果是頻繁更新的字段建了索引,更新字段的同時需要額外去更新索引
2、索引會占用比較大的磁盤空間去存儲
3、唯一性太差的字段也不適合做索引
索引這么快速的提升了查詢速度是怎么做到的呢?
索引的本質
MySQL官方對于索引的定義為:索引是幫助MySQL高效獲取數據的數據結構。即可以理解為:索引是數據結構。
?
我們知道,數據庫查詢是數據庫最主要的功能之一,我們都希望查詢數據的速度盡可能的快,因此數據庫系統的設計者會從查詢算法的角度進行優化。最基本的查詢算法當然是順序查找,當然這種時間復雜度為O(n)的算法在數據量很大時顯然是糟糕的,于是有了二分查找、二叉樹查找等。但是二分查找要求被檢索數據有序,而二叉樹查找只能應用于二叉查找樹,但是數據本身的組織結構不可能完全滿足各種數據結構。所以,在數據之外,數據庫系統還維護者滿足特定查找算法的數據結構,這些數據結構以某種方式引用數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
?
B-Tree和B+Tree
目前大部分數據庫系統及文件系統都采用B-Tree和B+Tree作為索引結構。
?
索引
索引的目的:提高查詢效率
原理:通過不斷的縮小想要獲得數據的范圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是我們總是通過同一種查找方式來鎖定數據。
數據結構:B+樹
圖解B+樹與查找過程:
?
如上圖,是一顆b+樹,關于b+樹的定義可以參見B+樹,這里只說一些重點,淺藍色的塊我們稱之為一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大于35的磁盤塊。真實的數據存在于葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點只不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35并不真實存在于數據表中。
?
b+樹的查找過程
如圖所示,如果要查找數據項29,那么首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間因為非常短(相比磁盤的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢,總計三次IO。真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。
?
b+樹性質
通過上面的分析,我們知道IO次數取決于b+數的高度h,假設當前數據表的數據為N,每個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N一定的情況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,如果數據項占的空間越小,數據項的數量越多,樹的高度越低。這就是為什么每個數據項,即索引字段要盡量的小,比如int占4字節,要比bigint8字節少一半。這也是為什么b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度下降,導致樹增高。當數據項等于1時將會退化成線性表
周天的一個小小學習過程分享出來,比較初級,如有錯誤還請大神們指教
---------------------?
作者:Mr_yaodefine?
來源:CSDN?
原文:https://blog.csdn.net/name_javahadoop/article/details/80469800?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
總結
以上是生活随笔為你收集整理的一次mysql大数据量查询 慢查询导致服务阻塞后的学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL 处理海量数据时的一些优化查询
- 下一篇: 白玉蜗牛(说一说白玉蜗牛的简介)