MySQL基本原理和使用技巧
本文是我在大半年前在前公司做團隊分享時的一個文件,寫得比較挫,當時分享講了2個小時,自己感覺講得還可以。最近前同事跑來問我還有沒有文件儲存,翻了舊電腦和硬碟才找出來,於是就想著分享一下。
一、MySQL整體結構
-
伺服器層(負責客戶端連線、授權認證、安全、執行緒管理等)
-
核心層(快取查詢、解析器、查詢優化器、函式)(儲存過程,觸發器,檢視)
-
儲存引擎層(MyISAM、InnoDB、Memory、Merge,負責資料的儲存和提取)
資料庫的全球排名情況
https://db-engines.com/en/ranking
本次講的大多是INNODB
mysql太多內容可講,每個點都一次分享都講不完。
沒有理解核心實現時的無法知道mysql怎麼工作,只知道儲存。
帶大家從外而內看透MySQL。
這個整體結構類似於springMvc中的controller service dao
- Connectors:不同語言中與 SQL 的互動
- Management Serveices & Utilities:系統管理和控制工具
- Connection Pool:連線池
- SQL Interface:SQL 介面(提供給儲存引擎層,類似於面向介面程式設計,SPI等)
- Parser:解析器
- Optimizer:查詢優化器
- Cache 和 Buffer:查詢快取
- Engine:儲存引擎
MyISAM和INNODB的區別
1、Innodb最大的特點: 支援事務處理與外來鍵和行級鎖
2、索引實現方式不同,MyISAM的索引和資料是分開的,並且索引是有壓縮的,記憶體使用率就對應提高了不少InnoDB 中不儲存表的具體行數,也就是說,執行select count() from table
3、對於AUTO_INCREMENT型別的欄位,InnoDB中必須包含只有該欄位的索引,但是在MyISAM表中,可以和其他欄位一起建立聯合索引
4、DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。
5、InnoDB 中不儲存表的具體行數,也就是說,執行select count(
關於MyISAM和InnoDB的其他相關
1、讀多寫少的,MyISAM的讀效能是比Innodb強不少
2、MySQL 4.0以上 myisam引擎就支援了full text search 全文搜尋
3、mysql版本號已經大於5.6.4了也就支援了innodb的全文搜尋
一條查詢語句的執行過程
二、MySQL的資料結構和原理
Questions
-
MySQL通過什麼資料結構實現?
-
為什麼要用這種資料結構實現?
-
我們如何最大化這種特性?如何利用這種特性來優化我們的資料庫設計和查詢?
- 常用的資料結構
線性結構:陣列、連結串列、雜湊表
樹形結構:二叉樹(平衡二叉樹、二叉查詢樹、完全二叉樹)、2-3樹、紅黑樹、B樹
圖形結構:有向圖、無向圖
二叉樹
-
若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
-
若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
-
任意節點的左、右子樹也分別為二叉查詢樹。
-
沒有鍵值相等的節點(no duplicate nodes)。
二分查詢\二叉樹查詢,時間複雜度o(lgn)
2-3樹
-
對於3節點,該節點儲存兩個key及對應value,以及三個指向左中右的節點
-
在最壞的情況下,也就是所有的節點都是2-node節點,查詢效率為lgN
-
在最好的情況下,所有的節點都是3-node節點,查詢效率為log3N約等於0.631lgN
在最壞的情況下,也就是所有的節點都是2-node節點,查詢效率為lgN
在最好的情況下,所有的節點都是3-node節點,查詢效率為log3N約等於0.631lgN
紅黑樹
-
紅色節點向左傾斜
-
一個節點不可能有兩個紅色連結
-
整個書完全黑色平衡,即從根節點到所以葉子結點的路徑上,黑色連結的個數都相同。
紅黑樹是2-3樹的一種簡單高效的實現
B樹
- 每一個節點都包含資料,元素離根節點餘越近訪問越快
B+樹
-
內部節點上不包含資料資訊
-
葉子結點都是相連的
對於一顆節點為N度為M的子樹,查詢和插入需要logM-1N ~ logM/2N次比較。這個很好證明,對於度為M的B樹,每一個節點的子節點個數為M/2 到 M-1之間,所以樹的高度在logM-1N至logM/2N之間。
這種效率是很高的,對於N=62*1000000000個節點,如果度為1024,則logM/2N <=4,即在620億個元素中,如果這棵樹的度為1024,則只需要小於4次即可定位到該節點,然後再採用二分查詢即可找到要找的值。
B樹和B+樹的排序圖區別
- 有哪些可能被用來實現MySQL的資料結構
有了上面的資料結構知識,可以知道MySQL會利用什麼資料結構實現了嗎?
磁碟上資料必須用一個三維地址唯一標示:柱面號、盤面號、塊號(磁軌上的盤塊)。
磁碟讀取資料是以盤塊(block)為基本單位的,一個block為4k
- InnoDB索引實現
主鍵索引
非主鍵索引
基於B+樹的資料結構給出的建議:
- 表的主鍵儘量用自增ID,不用隨機生成的
- 某些查詢可以使用覆蓋索引的,則可以減少一次回表查詢
三、MySQL隔離級別和MVCC實現原理
- Read Uncommitted(讀未提交)
- Read Committed(讀已提交)
- Repeatable Read(可重複讀)
- Serializable(序列化)
四、MySQL的鎖機制
常用的鎖的方式
- select … lock in share mode
- select … for update
樂觀鎖的使用例子:
update trade_id_log set max_trade_id=#maxTradeId# where owner_id=#ownerId# and max_trade_id = #originMaxTradeId#
看下面的SQL是否加鎖,如何加鎖:SQL1:select * from t1 where id = 10;
SQL2:delete from t1 where id = 10;
先拋兩個名詞:記錄鎖、間隙鎖 看下面幾種情況是怎麼加鎖的1.id列是主鍵,RC隔離級別
(X鎖是排他鎖)
2.id列是二級非唯一索引,RC隔離級別
3.id列是二級非唯一索引,RR隔離級別
4.id無索引,RR隔離級別
5.Serializable隔離級別
Serializable隔離級別,影響的是SQL1:select * from t1 where id = 10;6.思考一下這幾種情況
(1)id列是二級唯一索引,RC隔離級別;
(2)id列上沒有索引,RC隔離級別;
(3)id列是主鍵,RR隔離級別;
(4)id列是二級唯一索引,RR隔離級別;
7.分析一條複雜的SQL的加鎖方式(RR隔離級別)
–>
五、MySQL使用技巧
1.sql查詢優化,瞭解explain
(1)分頁問題:使用者需要檢視第50000頁的100條資料
解決方案一:
先通過覆蓋索引查對應的分頁資料的主鍵ID,再通過主鍵ID去查資料
解決方案二:
業務優化,不讓使用者選擇;或者只能上/下一頁翻動
explain select SQL_NO_CACHE * from product limit 5000000,100
\# 掃描的行:6512596
explain select SQL_NO_CACHE * from product where id > 7391753 limit 0,100
\# 掃描的行:3256298,記錄上一頁最後一條資料id,用於下一次的搜尋
(2)Group by優化
GROUP BY 預設會使用分組欄位排序(可能會檔案排序),取消排序使用order by null
如:explain select status,count(status) from trade30 group by status ;
改寫成 explain select status,count(status) from trade30 group by status order by null ;
2.ip儲存
select inet_aton("192.168.52.100");
select inet_ntoa(3232248932);
3.mysql程式 mysql函式(使用案例:自定義大量資料入庫(模擬陳胤的product資料))
自定義函式:生成隨機字串
DELIMITER &&
CREATE FUNCTION `randstring`(n INT) RETURNS varchar(255)
BEGIN
DECLARE chars_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE return_str varchar(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = concat(return_str,substring(chars_str , FLOOR(1 + RAND()*62 ),1));
SET i = i +1;
END WHILE;
RETURN return_str;
END
&&
4.自定義hash索引(crc32函式 crc64函式)使用案例:精確查詢某個固定的字串
CREATE TABLE `crc` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`article` varchar(512) DEFAULT NULL,
`value` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_V` (`value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
set @aa = "adsfhaklshfjdsafhasdkfyuqwo4623703241213846231891421354961238472318947123elrbmanvcuixgqwbelfjasdkcgsavdlfbasdkchadgsliubfja.sdkvhgvsi";
insert into crc VALUES(null,@aa,CRC32(@aa));
select * from crc where value = crc32(@aa);
5.避免資料庫插入重複記錄
(1)insert ignore into person (id,name,phone) VALUES (20,‘111’,‘12’);
(2)REPLACE into person (id,name,phone) VALUES (20,‘20’,‘20’);
(3)insert into person (id,name,phone) VALUES (32,‘3232’,‘3232’) ON DUPLICATE KEY UPDATE name=‘323232’;
6.樂觀鎖的使用
update trade_id_log set max_trade_id=#maxTradeId# where owner_id=#ownerId# and max_trade_id = #originMaxTradeId#
7.檢視的使用
刪除檢視
drop view if exists user_view;
建立檢視
create view user_view as select uid,uname,mobile from user_account;
查詢檢視
select * from user_view;
作者推薦部落格