1. 程式人生 > >MySQL索引管理及執行計劃

MySQL索引管理及執行計劃

索引管理

MySQL索引管理及執行計劃

第1章 索引介紹:

索引是對數據庫表中一列或者多了的值進行排序的一種結構,使用索引可以快速訪問數據庫表中的特定信息,如果想按特定職員的姓名來查找,則與他在表中搜索所有的行相比,索引有助於更快的獲取信息

索引的一個主要目的就是加快檢索表中的數據的方法,既能協助信息搜索者盡快找到符合限制條件的記錄ID的輔助數據結構

1.1 索引的類型介紹:

btree:B+樹索引 最為常用

hash:hash索引

fulltest:全文索引

rtree:r數索引

第2章 索引管理

2.1 B樹索引的分類:

主鍵索引:

數據庫表經常有一列或多列組合,其值唯一標識表中的每一行,該列稱為表的主鍵,在數據庫關系圖中為表定義主鍵將自動創建主鍵索引

,主鍵索引是唯一索引的特定類型

唯一索引:

是不允許期中任何兩行具有相同索引值的索引,當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創建的唯一索引與表一起保存,數據庫還可能防止添加將在表中創建重復鍵值的新數據

普通索引:

2.2 mysql中的約束索引:

2.2.1 主鍵索引:只能有一個主鍵

主鍵索引,列的內容是唯一值,高中學號

表創建的時候至少要有一個主鍵索引,最好和業務無關

2.2.2 普通索引:

加快查詢速度,工作中優化數據庫的關鍵

在合適的列上建立索引,讓數據查詢更加高效

2.2.3 唯一索引:

內容唯一,但不是關鍵

2.3 添加索引:

mysql> alter table people add index index_name(id);
mysql> alter table stu add index ind_mul(id);
mysql> create index inx on stu(gender);

2.4 刪除索引:

mysql> alter table stu drop index ind_mul;

2.5 查詢索引:

mysql> desc people;
mysql> show index from people;

2.6 主鍵索引的設置:

1. 建表時就設置

2. 建表沒有指定,後期修改

2.6.1 唯一鍵索引的創建:

mysql> alter table stu add unique key ind(name);

2.6.2 聯合索引的創建:

mysql> alter table stu add index ind_id_name(id,name);

聯合索引的特點:a;ab;abc 可以走索引

b;ac;bc;c 不走索引

原則是把最常用來作為條件查詢的列放在前面

2.6.3 前綴索引的創建:

create index ind_name on test(name(8));
alter table test add index ind_name(name(8));

2.6.4 什麽情況下推薦創建索引呢?

where   order by   group by   join  on

2.7 索引的企業應用場景:

2.7.1 企業優化思路:

1. 把一個大的不使用索引的sql語句安好功能進行拆分

2. 長的sql語句無法使用索引,能不能變成兩條端的sql語句,讓它分別使用上索引

3. sql語句功能的拆分和修改

4. 減少爛sql

5. 由運維和開發交流確認,共同確定如何改,最終由dba執行

6. 制定開發流程

2.7.2 不適合建立索引的場景:

1. 唯一值少的裂傷不適合建立索引或者建立索引會導致效率低,例如性別列

2. 小表可以不創建索引,100條記錄

3. 對於數據倉庫,大量全表掃描的情況,建立索引範圍會慢

第3章 執行計劃獲取及分析

3.1 explain 調取執行計劃

查看是否走了索引:

mysql> explain select name from stu;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | stu   | index | NULL          | ind  | 63      | NULL |    2 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
mysql> explain select id from stu where id=1;
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | stu   | ref  | ind_mul       | ind_mul | 5       | const |    1 | Using index |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+

allindex的類型,我們通常認為,索引的創建不夠合理,起碼達到range級別以上

3.2 type 訪問類型的種類:

3.2.1 ALL:

mysql將遍歷全表以紮到匹配的行

3.2.2 index:

索引範圍掃描,indexALL類型之遍歷索引樹

3.2.3 range:

索引範圍掃描,對索引的掃描開始於某一點,返回匹配值域的行,這種索引範圍掃描是帶有between或者where子句裏帶有<>查詢,

3.2.4 ref:

使用非唯一索引掃描或者唯一索引的前綴掃描,返回匹配某個單獨值的記錄行

3.2.5 eq_ref:

類似ref區別就在於使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者unique key 作為關聯條件

3.2.6 const/system:

mysql對查詢某部分進行優化,並轉換為一個常亮時,使用這些類似訪問,如將主鍵置於where列表中,mysql就能將該查詢轉換為一個常量

3.2.7 null:

mysql在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列表裏選取最小值可以通過單獨索引查找完成

type類型從上到下,性能由差到好

3.3 查看表中唯一值的數量:

mysql> select count(distinct user,host) from mysql.user;
+---------------------------+
| count(distinct user,host) |
+---------------------------+
|                         5 |
+---------------------------+
1 row in set (0.00 sec)

第4章 數據庫索引設計的原則:

為了使索引的使用效率更高,在創建索引時,必須考慮在哪些字段上創建索引和創建什麽類型的索引

4.1 索引設計重要原則:

4.1.1 選擇唯一性索引

唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄

例如,學生表中的學生號是具有唯一性的字段,為該字段建立唯一性索引可以很快的確定某個學生的信息,如果使用姓名的話,又可能會存在同名的現象,從而降低查詢速度

主鍵索引和唯一鍵索引,在查詢中是效率最高的

4.1.2 為經常需要排序,分組和聯合操作的字段建立索引

經常需要order by group by distinctuntion等操作的字段,排序操作會浪費很多時間,如果為其建立索引,可以有效的避免排序操作

4.1.3 為經常查詢條件的字段建立索引

如果某個字段上經常用來做查詢條件,那麽該字段的查詢速度回影響整個表的查詢速度,因此,為這樣的字段建立索引,可以提高整個表的查詢速度

4.1.4 盡量使用前綴來索引

如果索引字段的值很長,最好使用值的前綴來索引,例如:testblog類型的字段,進行全文檢索會很浪費時間,如果只檢索字段的前面的若幹個字符,這樣可以提高檢索速度

4.1.5 限制索引的數目

索引的數目並不是越多越好,每個索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大,修改表時,對索引的重構和更新很麻煩,越多的索引,會使更新表變得很浪費時間

4.1.6 盡量使用數據量少的索引

如果索引的值很長,那麽查詢的速度必然會受到影響,例如:對弈char(100)類型的字段進行全文檢索需要的時間肯定要比對char(10)類型的字段需要的時間更多

4.1.7 刪除不在使用或者很少使用的索引

表中的數據被大量更新,或者數據的使用方式被改變後,原有的一些索引可能不在需要,數據庫管理員應當定期找出這些索引,並刪除,從而減少索引對更新操作的影響

4.2 索引開發的規範:

不走索引的情況:

4.2.1 沒有查詢條件,或者查詢條件沒有建立索引

在業務數據庫中,數據量大的是沒有必要進行全表掃描的,一定程度上講,全表掃描對用戶體驗就非常痛苦的,同時對服務器也是毀滅性的;又或者索引建立的但是查詢條件沒有where等條件

4.2.2 查詢結果集是原表中的大部分數據,達到了30%以上

查詢結果集超過了總行數的30%,就沒有必要走索引了

例如
:select * from test where id>500000;

如果業務允許的情況下,可以加上limit進行控制,如果因為業務的原因沒有辦法改寫方案,就可以放到redis

4.2.3 索引本身失效,統計數據不真實

索引有自我維護的能力,對於表的變化內容比較頻繁的情況下,可能會出現索引失效

4.2.4 查詢條件使用函數在索引列上,或者對索引列進行運算,運算包括(+ - * /)

盡量不要在查詢條件上進行運算,算好了在假如查詢條件中

4.2.5 隱式轉換導致索引失效,這一點應當引起重視,也是開發中經常遇到的錯誤

由於表的字段name定義為varchar(20),但是在查詢時把該字段作為number類型以where條件傳給數據庫,這樣會導致索引失效

例如:在查詢name的字段信息時,因為是字符串的類型,where就需要加上單引號,但是sql語句忘記加上,就會導致索引失效

select * from test where tu_mdn=13333333333;
正確的寫法: select * from test where tu_mdn=’13333333333’;
案例演示:
mysql> alter table tab add index inx_tel(telnum);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
mysql> desc tab;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | YES  |     | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| telnum | varchar(20) | YES  | MUL | NULL    |       |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
 
mysql> select * from tab where telnum='1333333';
+------+------+---------+
| id   | name | telnum  |
+------+------+---------+
|    1 | a    | 1333333 |
+------+------+---------+
1 row in set (0.00 sec)
 
mysql> select * from tab where telnum=1333333;
+------+------+---------+
| id   | name | telnum  |
+------+------+---------+
|    1 | a    | 1333333 |
+------+------+---------+
1 row in set (0.00 sec)
 
mysql> explain  select * from tab where telnum='1333333';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra                 |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
|  1 | SIMPLE      | tab   | ref  | inx_tel       | inx_tel | 63      | const |    1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)
 
mysql> explain  select * from tab where telnum=1333333;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | tab   | ALL  | inx_tel       | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
 
mysql> explain  select * from tab where telnum=1555555;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | tab   | ALL  | inx_tel       | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
 
mysql> explain  select * from tab where telnum='1555555';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra                 |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
|  1 | SIMPLE      | tab   | ref  | inx_tel       | inx_tel | 63      | const |    1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

4.2.6 <>,not in 不走索引

<> 的作用是不等於

mysql> select * from stu;
+--------+------+------+------+------+---------+--------+------+-------+
| stu_id | id   | name | QQ   | age  | tel_num | gender | addr | state |
+--------+------+------+------+------+---------+--------+------+-------+
|   NULL |    7 | NULL | NULL | NULL |    NULL | NULL   | NULL |     1 |
|   NULL | NULL | xiao | NULL | NULL |    NULL | NULL   | NULL |     1 |
+--------+------+------+------+------+---------+--------+------+-------+
2 rows in set (0.00 sec)
 
mysql> select * from stu where id <> '7';
Empty set (0.00 sec)

單獨的>,<,in 有可能走,也有可能不走,和結果集有關,盡量結合業務添加limit

or或者in 盡量改寫成union

EXPLAIN  SELECT * FROM teltab WHERE telnum   IN ('110','119');

改寫成:

EXPLAIN SELECT * FROM teltab WHERE telnum='110'
UNION ALL
SELECT * FROM teltab WHERE telnum='119'

4.2.7 like “%_” 百分號在前面,不走索引

mysql> explain select * from stu where name like '%xiao';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | stu   | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
 
mysql> explain select * from stu where name like 'xiao%';
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
|  1 | SIMPLE      | stu   | range | ind           | ind  | 63      | NULL |    1 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
1 row in set (0.00 sec)

%號一類的搜索請求,可以使用elasticsearch

4.2.8 單獨引用聯合索引裏非第一位置的索引列

聯合索引案例:

CREATE TABLE t1 (id INT,NAME VARCHAR(20),age INT ,sex ENUM('m','f'),money INT);
 
ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex);
 
DESC t1
SHOW INDEX FROM t1
(a,b,c)
a   ab  abc
ac
bc
b  c
-----------------------------

走索引:

EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30  AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30  ;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30  AND sex='m';    ----部分走索引


不走索引:

EXPLAIN SELECT  NAME,age,sex,money FROM t1 WHERE  age=20
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE  age=30  AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE   sex='m';

4.2.9 blobtext類型的列只能創建前綴索引

4.2.10 mysql目前不支持函數索引

4.2.11 join語句中join條件字段類型不一致的時候mysql無法使用索引


MySQL索引管理及執行計劃