Mysql學習筆記(九)索引查詢優化


PS:上網再次看了一下數據庫關於索引的一些細節...感覺自己學的東西有點少...又再次的啃了啃索引....

學習內容:

索引查詢優化...

上一章說道的索引還不是特別的詳細,再補充一些具體的細節...

1.B-Tree索引...

B-tree結構被稱為平衡多路查找樹...其數據結構為:

 

  這就是其數據結構圖。。。我們沒必要完全的理解其中的原理。。並且我也不會做過多的原理介紹。。。我們只需要知道數據庫是以這種方式進行存儲數據的就可以了...

 

mysql> create table title
    -> (
    ->    id int not null,
    ->    title varchar(255) not null,
    ->    from_date date not null,
    ->    key(id),
    ->    key(title),
    ->    key(from_date)
    -> );
//建立一個表格。。。有三個主鍵..。有主鍵必然要使用到索引...
介紹一下查詢方式...
1.全列匹配...
mysql>expla select * from title where id=1000 and title='gogoing' and from_date='1992-01-01';
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref               | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
|  1 | SIMPLE      | titles | const | PRIMARY       | PRIMARY | 59      | const,const,const |    1 |       |
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
2.最左前綴索引...
explain select * from title where id=1001;
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
| id | select_type | table  | type | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | titles | ref  | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
最左前綴原則是當索引用到多個列的時候,只有組成最左前綴的部分才能被使用到..上面只用到了第一列...
3.匹配的索引列使用了精確匹配。。。但是中間有部分列沒有被給出...
explain select * from title where id=1002 and from_date='1998-01-01';
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | titles | ref  | PRIMARY       | PRIMARY | 4       | const |    1 | Using where |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
這樣只會走第一個索引id,而from_date將不走索引。。由於沒有給出title的值,所以無法構成最左前綴原則,因此from_date成為不走索引...
我們可以使用兩種方式解決這個問題....使用IN將title的所有值都包括在其中...
EXPLAIN SELECT * FROM employees.titles
WHERE emp_no='1005'
AND title IN ('title1的值','title2的值'......)
AND from_date='1986-06-26';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 59      | NULL |    7 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
這樣就不會出現不走索引的情況了...但是如果title的值過多,那么in這種方式就不能使用..因此解決這個問題的另一種方式就是建立輔助索引....
4.查詢的時候沒有指定索引的第一列...
explain select * from title where from_date='1995-01-26';//這個結果很明顯,就是不走索引...
5.匹配某列前綴的字符串..
explain select * from title where id=1008 and title like 'S%';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 56      | NULL |    1 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
6.使用范圍查詢...
explain select * from title where id>1010;范圍列可以使用索引,但是必須是最左前綴..並且如果同一個查詢語句使用了兩個范圍索引,那么后面的范圍將成為不走索引..
explain select * from title where id>1010 and title='gogoing' and from_date between '1990-01-01' and '1998-01-01';
還有一種情況就是如下面代碼..
explain select * from where id between 1000 and 1010 and title='gogoing' and from_date between '1998-01-01' and '2010-01-01';
上面這種情況就變成了第一個就成為了多值匹配,而后面那個范圍成為了范圍匹配...同樣都是兩個范圍匹配,和上面的情況就不同了..這個我至今沒弄明白..雲里霧里的...如果有大牛會的話請告訴我。。。
7.帶有表達式的查詢方式...
如果查詢語句中含有表達式,那么將成為不走索引。。。(除一些特殊方式)。。。
EXPLAIN SELECT * FROM employees.titles WHERE emp_no - 1='10000';
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | titles | ALL  | NULL          | NULL | NULL    | NULL | 443308 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
不走索引...

 

2.Hash索引..

MySQL中,只有Memory存儲引擎顯示支持hash索引,是Memory表的默認索引類型,盡管Memory表也可以使用B-Tree索引。 Memory存儲引擎支持非唯一hash索引,這在數據庫領域是罕見的,如果多個值有相同的hash code,索引把它們的行指針用鏈表保存到同一個hash表項中。。

hash索引就是講我們存儲的數據按照一定的哈希函數來進行保存在一個指針數據中,當我們需要查找的時候,調用hash函數,找到我們需要的數據的指針,通過這個指針,我們就可以訪問其中的數據信息了..hash的指針數據是有序的,但對應的數據信息是無序的...

Hash索引有以下一些限制:
(1)由於索引僅包含hash code和記錄指針,所以,MySQL不能通過使用索引避免讀取記錄。但是訪問內存中的記錄是非常迅速的,不會對性造成太大的影響。
(2)不能使用hash索引排序。
(3)Hash索引不支持鍵的部分匹配,因為是通過整個索引值來計算hash值的。
(4)Hash索引只支持等值比較,例如使用=,IN( )和<=>。對於WHERE price>100並不能加速查詢。

3.索引的使用范圍...

那么我們到底什么情況下使用索引呢?有兩種判斷的方式...

i.看了別人的博客說。。一般當我們存儲的數據不超過2000條的時候,我們是沒有必要使用索引的...

ii.索引的選擇性。。。

索引的選擇性=表中列的唯一鍵的數量/表的行數...這個數值越接近於1越好...就比如說主鍵,毋庸置疑絕對是1..所以有了主鍵我們必須要使用索引..

上面說到了輔助索引...

4.那么什么是輔助索引呢?簡單的介紹一下....

不同的存儲引擎對應的輔助索引的結構圖也是不同的。。。其實輔助索引和主索引並沒有過大的區別,只是主索引要求key值唯一。。輔助索引的key值可以重復....並且二者構成的存儲結構也基本相同,都是一棵b+tree。。。每一個數據記錄都保存在一個地址當中,這個地址的獲取由地址節點的父節點來存儲...一層扣一層。。。就形成了樹狀結構...

5.聚簇索引..

  Innobe存儲引擎支持聚簇索引,這種索引方式也是以b+tree為存儲結構,但是他和myisam存儲引擎完全不同,因為myisam不支持聚簇索引,支持非聚簇索引...

Innobe的數據文件本身就是索引文件..這個b+tree的data數據域完全保存着數據記錄,並且也保存着索引的key值,那么當我們找到了key值的時候,我們就可以直接訪問數據文件。。。因為數據文件的本身就是主索引...

而myisam存儲引擎的數據文件和索引文件是完全分離的,b+tree的data數據域保存着記錄數據文件的地址,當我們要通過索引key的值查找數據的時候,我們需要經過找到這個key對應的data數據域的指針值,然后我們通過指針的值去訪問我們想要的數據信息...

聚簇索引和非聚簇索引的區別圖...Primary key表示主索引...Secondary key表示輔助索引...

 

6.覆蓋索引

簡單的介紹一下覆蓋索引的有點。。。自己學的也不是特別的透徹,只是做簡單的介紹...

如果索引包含滿足查詢的所有數據,就稱為覆蓋索引。覆蓋索引是一種非常強大的工具,能大大提高查詢性能。只需要讀取索引而不用讀取數據有以下一些優點:
(1)索引項通常比記錄要小,所以MySQL訪問更少的數據;
(2)索引都按值的大小順序存儲,相對於隨機訪問記錄,需要更少的I/O;
(3)大多數據引擎能更好的緩存索引。比如MyISAM只緩存索引。
(4)覆蓋索引對於InnoDB表尤其有用,因為InnoDB使用聚集索引組織數據,如果二級索引中包含查詢所需的數據,就不再需要在聚集索引中查找了。
覆蓋索引不能是任何索引,只有B-TREE索引存儲相應的值。而且不同的存儲引擎實現覆蓋索引的方式都不同,並不是所有存儲引擎都支持覆蓋索引(Memory和Falcon就不支持)。
對 於索引覆蓋查詢(index-covered query),使用EXPLAIN時,可以在Extra一列中看到“Using index”。

7.利用索引進行排序...

MySQL中,有兩種方式生成有序結果集:一是使用filesort,二是按索引順序掃描。利用索引進行排序操作是非常快的,而且可以利用同一索引同時進 行查找和排序操作。當索引的順序與ORDER BY中的列順序相同且所有的列是同一方向(全部升序或者全部降序)時,可以使用索引來排序。如果查詢是連接多個表,僅當ORDER BY中的所有列都是第一個表的列時才會使用索引。其它情況都會使用filesort。

 

create table actor(

actor_id int unsigned NOT NULL AUTO_INCREMENT,

name      varchar(16) NOT NULL DEFAULT '',

password        varchar(16) NOT NULL DEFAULT '',

PRIMARY KEY(actor_id),

 KEY     (name)

) ENGINE=InnoDB

insert into actor(name,password) values('cat01','1234567');

insert into actor(name,password) values('cat02','1234567');

insert into actor(name,password) values('ddddd','1234567');

insert into actor(name,password) values('aaaaa','1234567');

mysql> explain select actor_id from actor order by actor_id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | actor | index | NULL          | PRIMARY | 4       | NULL |    4 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

mysql> explain select actor_id from actor order by password;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | actor | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

mysql> explain select actor_id from actor order by name;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | actor | index | NULL          | name | 34      | NULL |    4 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

 


免責聲明!

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



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