初始化測試數據
創建一個測試用的表
create table dept(
id int primary key auto_increment ,
deptName varchar(32) not null unique,
salary decimal(12,6) not null,
remark varchar(256),
createDate date);
使用存儲過程在表中插入一萬條數據
DELIMITER $$ CREATE /*[DEFINER = { user | CURRENT_USER }]*/ PROCEDURE `test`.`insert_data`() /*LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string'*/ BEGIN DECLARE i INT DEFAULT 0; WHILE(i<=10000) DO BEGIN SELECT i; SET i=i+1; INSERT INTO dept(deptName,salary,createDate,remark) VALUES(i,20000,NOW(),'test'); END ; END WHILE; END$$
通過EXPLAIN分析SQL的執行計划
type:表示MySQL在表中找到所需行的方式,或者叫訪問類型,常見類型如下(從左到右,性能由差到好)
ALL index range ref eq_ref const,system NULL
ALL: 全表掃描
index: 索引全掃描
range:索引范圍掃描
ref:使用非唯一索引掃描
eq_ref:使用唯一索引掃描
const,system:單表中最多只有一個匹配行
以上:通過explain分析type是ALL 是性能最差的一種 以下:開始優化。
MySQL中BTREE索引的用法
普通的BTREE索引
優化前 explain select remark from dept where deptName = ?; type ALL
增加索引 ALTER TABLE dept ADD INDEX index_remark (`remark`);
優化測試 explain select remark from dept where deptName = ?; type ref
聯合BTREE索引
增加聯合索引 ALTER TABLE dept ADD INDEX index_all (`deptName`,`remark`,`createDate`);
explain select deptName,remark,createDate from dept where deptName='2' and remark = 'test'and createDate ='2018-07-22'; type ref
但是explain select deptName,remark,createDate from dept where remark = 'test'and createDate ='2018-07-22'; type index
——type從ref(使用非唯一索引掃描)變成了index(索引全掃描),
上面兩個SQL 索引相同 Type不同是因為 BTREE索引中匹配最左前綴 比如給col1+col2+col3字段上加聯合索引能夠被包含
col1+col2 、col1+col2+col3、col1+col3使用(順序沒有影響 比如 where col1=? and col2=? 和 where col2=? and col1=? 結果一樣)
使用聯合索引 相當於一下子創建了如上的三個索引,這就是聯合索引的好處
存在索引但不能使用索引的經典場景
例句:explain select deptName,remark,createDate from dept where deptName='2' and remark = 'test'and createDate ='2018-07-22'; type ref
下面是反面教材:
1.以%開頭的LIKE查詢不能使用BTREE索引
explain select deptName,remark,createDate from dept where deptName like'%2' and remark = 'test'and createDate ='2018-07-22'; type index
2.數據類型出現隱式轉換時也不能使用索引
explain select deptName,remark,createDate from dept where deptName =2 and remark = 'test'and createDate ='2018-07-22'; type index
3.復合索引時 不符合最左匹配原則(上面已經提到)
explain select deptName,remark,createDate from dept where remark = 'test'and createDate ='2018-07-22'; type index
復合索引最左匹配原則的成因:
Mysql創建復合索引的規則是首先會對復合索引最左邊,也就是第一個字段的索引進行排序,
在第一個字段排序的基礎上,在對第二個字段進行排序,所以直接使用第二個字段是沒有順序的
4.用or分隔開的條件,如果or前的條件中的列有索引,后面的列中沒有索引,那么涉及到的索引都不會使用到
explain select deptName,remark,createDate from dept where deptName ='2' and remark = 'test'and createDate ='2018-07-22' or salary =200; type ALL
建議or之間的每個條件都要有索引
優化 Order By語句、Group By語句 和Limit語句
1)Order By
order by 字段混合使用DESC ASC 不會使用索引
select * from table order by key1 desc,key2 asc (盡量不要出現這種混合排序)
Where條件過濾的關鍵字和Order by中所使用的不同 不會使用索引
select * from table where key2 = ? order by key1 (order by 出現的關鍵字 盡量 在where條件中也出現)
2)Grouy By
當我們的SQL語句需要Group By分組時: 默認情況下,mysql在使用group by之后,會產生臨時表,而后進行排序(此處排序默認是快排),這會消耗大量的性能
group by column 默認會按照column分組, 然后根據column升序排列; group by column order by null 則默認按照column分組,然后根據標的主鍵ID升序排列
explain分析SQL的時候 Extra那一列有時候會出現 using Filesort表示需要額外的排序(對 group by 產生臨時表的排序 此時我強制order by salary 才出現Using filesort)
我用Mysql8.0做實驗,發現grouy by 默認是按照主鍵ID升序排列,而不是group的column,8.0的版本 MySQL應該做了優化
3) Limit
為什么數據庫中的B+樹索引能提高查詢速度
比如一本比較厚的書,我們需要找到對應的知識點,我們的習慣一般都是先看目錄,根據目錄去找到對應的知識點。試想一下,假如這本比較厚的書沒有目錄,我們就需要從前面到后面一頁一頁地找,直到找到對應的知識點,這個過程估
計得耗費一段時間了。
B+ 樹索引就是鏈接中的 B+ 樹發展而來的。在數據庫中,B+ 樹的高度一般都在 2 ~ 4 層,所以查找某一行數據最多只需要 2 到 4 次 IO。而沒索引的情況,需要逐行掃描,明顯效率低很多,這也就是為什么添加索引能提高查詢速度。
B+ 樹索引並不能找到一個給定鍵值的具體行,B+ 樹索引能找到的只是被查找數據行所在的頁。然后數據庫通過把頁讀入到緩沖池(buffer pool)中,在內存中通過二分查找法進行查找,得到需要的數據。
InnoDB 中 B+ 樹索引分為聚集索引和輔助索引,我們再繼續了解這兩種索引的特點。
B+索引和Hash索引的區別,主鍵索引和普通索引的區別
1)B+索引和Hash索引:
B+索引的數據結構是紅黑樹,查詢的時間復雜度是Ologn級別的 Hash索引的存儲數據結構是哈希表,查詢時間復雜度是O(1)級別的,
我們之所以用B+索引是因為Hash無序,不支持范圍查找和排序功能
2)主鍵索引和普通索引的區別:
平時我們用索引的時候 進來用主鍵查詢:因為主鍵索引的data存的是那一行的數據(innodb引擎),而普通索引(輔助索引)的data存的是主鍵,需要通過主鍵回表再次查詢