MySQL索引詳解




什麼是索引?

1、索引

索引是表的目錄,在查找內容之前可以先在目錄中查找索引位置,以此快速定位查詢數據。對於索引,會保存在額外的文件中。

2、索引,是數據庫中專門用於幫助用戶快速查詢數據的一種數據結構。類似於字典中的目錄,查找字典內容時可以根據目錄查找到數據的存放位置,然後直接獲取即可。

索引由數據庫中一列或多列組合而成,其作用是提高對錶中數據的查詢速度
索引的優點是可以提高檢索數據的速度
索引的缺點是創建和維護索引需要耗費時間
索引可以提高查詢速度,會減慢寫入速度

索引分類

1.普通索引
2.唯一索引
3.全文索引
4.單列索引
5.多列索引
6.空間索引
7.主鍵索引
8.組合索引

  • 普通索引:僅加速查詢
  • 唯一索引:加速查詢 + 列值唯一(可以有null)
  • 主鍵索引:加速查詢 + 列值唯一 + 表中只有一個(不可以有null)
  • 組合索引:多列值組成一個索引,
    專門用於組合搜索,其效率大於索引合併
  • 全文索引:對文本的內容進行分詞,進行搜索

索引合併,使用多個單列索引組合搜索
覆蓋索引,select的數據列只用從索引中就能夠取得,不必讀取數據行,換句話說查詢列要被所建的索引覆蓋

如何創建索引?記住一個單詞—explain

創建表的時候創建索引

    CREATE TABLE tbl_name( 
字段名稱 字段類型 [完整性約束條件],
,,,,
[UNIQUE|FULLTEXT|SPATIAL] INDEX|KEY索引名稱
[ASC|DESC]
);

在已經存在的表上創建索引:

1.CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名稱 ON 表名{字段名稱[(長度)] [ASC|DESC]} 
2.ALTER TABLE tbl_name ADD [UNIQUE|FULLTEXT|SPATIAL] INDEX索引名稱(字段名稱[(長度)][ASC|DESC]);

如何刪除索引?

DROP INDEX 索引名稱 ON tbl_name

1.普通索引

普通索引僅有一個功能:加速查詢

創建表+索引

create table in1( 
nid int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
extra text,
index ix_name (name)
)

創建索引

create index index_name on table_name(column_name)

刪除索引

drop index_name on table_name;

查看索引

show index from table_name;

注意:對於創建索引時如果是BLOB 和 TEXT 類型,必須指定length。

create index ix_extra on in1(extra(32));

2、唯一索引

唯一索引有兩個功能:加速查詢 和 唯一約束(可含null)

創建表+唯一索引

create table in1( 
nid int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
extra text,
unique ix_name (name)
)

創建唯一索引

create unique index 索引名 on 表名(列名)

刪除唯一索引

drop unique index 索引名 on 表名

3、主鍵索引

主鍵有兩個功能:加速查詢 和 唯一約束(不可含null)

創建表+創建主鍵

create table in1( 
nid int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
extra text,
index ix_name (name)
)

OR

create table in1(
nid int not null auto_increment,
name varchar(32) not null,
email varchar(64) not null,
extra text,
primary key(ni1),
index ix_name (name)
)

創建主鍵

alter table 表名 add primary key(列名);

刪除主鍵

alter table 表名 drop primary key; 
alter table 表名 modify 列名 int, drop primary key;

4、組合索引

組合索引是將n個列組合成一個索引

其應用場景爲:頻繁的同時使用n列來進行查詢,如:where n1 = ‘alex’ and n2 = 666。

創建表

create table in3( 
nid int not null auto_increment primary key,
name varchar(32) not null,
email varchar(64) not null,
extra text
)

創建組合索引

create index ix_name_email on in3(name,email);

如上創建組合索引之後,查詢:

  • name and email  – 使用索引
  • name                 — 使用索引
  • email                 — 不使用索引

注意:對於同時搜索n個條件時,組合索引的性能好於多個單一索引合併。

相關命令

- 查看錶結構 
desc 表名
  • 查看生成表的SQL
    show create table 表名

  • 查看索引
    show index from 表名

  • 查看執行時間
    set profiling = 1;
    SQL...
    show profiles;

使用索引和不使用索引

由於索引是專門用於加速搜索而生,所以加上索引之後,查詢效率會快到飛起來。


# 有索引
mysql> select * from tb1 where name = 'wupeiqi-888';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name | email | radom | ctime |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 889 | wupeiqi-888 | [email protected] | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (0.00 sec)

# 無索引
mysql> select * from tb1 where email = '[email protected]';
+-----+-------------+---------------------+----------------------------------+---------------------+
| nid | name | email | radom | ctime |
+-----+-------------+---------------------+----------------------------------+---------------------+
| 889 | wupeiqi-888 | [email protected] | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
+-----+-------------+---------------------+----------------------------------+---------------------+
1 row in set (1.23 sec)

正確使用索引

數據庫表中添加索引後確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,如果以錯誤的方式使用,則即使建立索引也會不奏效。

即使建立索引,索引也不會生效:

- like '%xx' 
select * from tb1 where name like '%cn';
- 使用函數
select * from tb1 where reverse(name) = 'wupeiqi';
- or
select * from tb1 where nid = 1 or email = '[email protected]';
特別的:當or條件中有未建立索引的列才失效,以下會走索引
select * from tb1 where nid = 1 or name = 'seven';
select * from tb1 where nid = 1 or email = '[email protected]' and name = 'alex'
- 類型不一致
如果列是字符串類型,傳入條件是必須用引號引起來,不然...
select * from tb1 where name = 999;
- !=
select * from tb1 where name != 'alex'
特別的:如果是主鍵,則還是會走索引
select * from tb1 where nid != 123
- >
select * from tb1 where name > 'alex'
特別的:如果是主鍵或索引是整數類型,則還是會走索引
select * from tb1 where nid > 123
select * from tb1 where num > 123
- order by
select email from tb1 order by name desc;
當根據索引排序時候,選擇的映射如果不是索引,則不走索引
特別的:如果對主鍵排序,則還是走索引:
select * from tb1 order by nid desc;
  • 組合索引最左前綴
    如果組合索引爲:(name,email)
    name and email -- 使用索引
    name -- 使用索引
    email -- 不使用索引

其他注意事項

- 避免使用select * 
- count(1)或count(列) 代替 count(*)
- 創建表時儘量時 char 代替 varchar
- 表的字段順序固定長度的字段優先
- 組合索引代替多個單列索引(經常使用多個條件查詢時)
- 儘量使用短索引
- 使用連接(JOIN)來代替子查詢(Sub-Queries)
- 連表時注意條件類型需一致
- 索引散列值(重複少)不適合建索引,例:性別不適合

limit分頁

無論是否有索引,limit分頁是一個值得關注的問題

每頁顯示10條: 
當前 118 120, 125

倒序:
大 小
980 970 7 6 6 5 54 43 32

21 19 98
下一頁:

數據庫查詢優化索引的一些注意點
儘量不要在where 條件之後使用函數來作爲查詢條件,因爲這樣做會使得該查詢字段的索引失效

在做查詢的時候如果in條件中仍然有select子查詢,那麼我們應該使用連接查詢join代替子查詢,子查詢會很影響查詢的效率

多表查詢時把數據量最大的表最後連接。或者直接將之前數據量較小的表都連接之後在括號外再去連接數據量特別大的那張表,這樣會避免數據量大的表進行全表查找。

對於查詢佔主要的應用來說,索引顯得尤爲重要。很多時候性能問題很簡單的就是因爲我們忘了添加索引而造成的,或者說沒有添加更爲有效的索引導致。如果不加索引的話,那麼查找任何哪怕只是一條特定的數據都會進行一次全表掃描,如果一張表的數據量很大而符合條件的結果又很少,那麼不加索引會引起致命的性能下降。但是也不是什麼情況都非得建索引不可,比如性別可能就只有兩個值,建索引不僅沒什麼優勢,還會影響到更新速度,這被稱爲過度索引。

多條件添加複合索引比如有一條語句是這樣的:select * from users where area=’beijing’ and age=22;

如果我們是在area和age上分別創建單個索引的話,由於mysql查詢每次只能使用一個索引,所以雖然這樣已經相對不做索引時全表掃描提高了很多效

率,但是如果在area、age兩列上創建複合索引的話將帶來更高的效率。如果我們創建了(area, age,

salary)的複合索引,那麼其實相當於創建了(area,age,salary)、(area,age)、(area)三個索引,這被稱爲最佳左前綴

特性。因此我們在創建複合索引時應該將最常用作限制條件的列放在最左邊,依次遞減。

alter table users add index area_age_salary(area,age,salary)

索引不會包含有NULL值的列

只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值爲NULL。

使用短索引

對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的 列,如果在前10 個或20 個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。

alter table users add index index_title(title(10))

排序的索引問題

mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;儘量不要包含多個列的排序,如果需要最好給這些列創建複合索引。

like語句操作

一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。

不要在列上進行運算

select * from users where YEAR(adddate)

不使用NOT IN操作

NOT IN和操作都不會使用索引將進行全表掃描。NOT IN可以NOT EXISTS代替

儘量少用or條件

or條件會使條件帶索引的失效,如果想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引

select * from order where id=10 or user_id=88 假如id爲索引user_id不是索引則此條件查詢索引失效,如果想讓索引有效user_id也得設爲索引

如果列類型爲字符串,則一定要在條件中將數據使用引號引用起來,否則不使用索引

select * from user where user_name=111 需改爲 select * from user where user_name=’111’

不要在索引字段上使用not,<>,!=

不要在索引列上使用is null 和is not null

不要在索引列上出現數據類型轉換

MySql 各種存儲引擎的特性對照詳單:
這裏寫圖片描述
從中我們能夠看出,

InnoDB 支持事務。支持行級別鎖定。支持 B-tree、Full-text 等索引。不支持 Hash 索引。
MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引。不支持 Hash 索引;
Memory 不支持事務,支持表級別鎖定。支持 B-tree、Hash 等索引,不支持 Full-text 索引。
NDB 支持事務,支持行級別鎖定。支持 Hash 索引。不支持 B-tree、Full-text 等索引;
Archive 不支持事務。支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章