MySQL如何使用索引


初始化測試數據

創建一個測試用的表

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存的是主鍵,需要通過主鍵回表再次查詢


免責聲明!

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



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