mysql索引的新手入門詳解(轉)

原文:http://www.javashuo.com/article/p-rxeunrdc-bc.htmlmysql

一、索引

1.一、簡要

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

  • 索引是數據庫中專門用於幫助用戶快速查詢數據的一種數據結構。相似於字典中的目錄,查找字典內容時能夠根據目錄查找到數據的存放位置,而後直接獲取便可。數據庫

1.二、索引選取類型

①、越小的數據類型一般更好:越小的數據類型一般在磁盤、內存和CPU緩存中都須要更少的空間,處理起來更快。緩存

②、簡單的數據類型更好:整型數據比起字符,處理開銷更小,由於字符串的比較更復雜。網絡

③、儘可能避免NULL:應該指定列爲NOT nuLL,在MySQL中, 含有空值的列很難進行查詢優化,由於它們使得索引、索引的統計信息以及比較運算更加複雜mysql優化

1.三、什麼場景不適合建立索引

​ ①、對於那些在查詢中不多使用或者參考的列不該該建立索引。這是因 爲,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。數據結構

​ ②、對於那 些只有不多數據值的列也不該該增長索引。由於原本結果集合就是至關於全表查詢了,因此沒有必要。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比 例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。
③、對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多。
④、當修改性能遠遠大於檢索性能時,不該該建立索 引。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。因 此,當修改性能遠遠大於檢索性能時,不該該建立索引。
⑤、不會出如今where條件中的字段不應創建索引。性能

1.四、什麼樣的字段適合建立索引

​ ①、表的主鍵、外鍵必須有索引;外鍵是惟一的,並且常常會用來查詢
②、數據量超過300的表應該有索引;
③、常常與其餘表進行鏈接的表,在鏈接字段上應該創建索引;常常鏈接查詢,須要有索引
④、常常出如今Where子句中的字段,加快判斷速度,特別是大表的字段,應該創建索引,創建索引,通常用在select ……where f1 and f2 ,咱們在f1或者f2上創建索引是沒用的。只有兩個使用聯合索引纔能有用
⑤、常常用到排序的列上,由於索引已經排序。
⑥、常常用在範圍內搜索的列上建立索引,由於索引已經排序了,其指定的範圍是連續的測試

二、索引優缺點

2.一、優勢

  • 索引由數據庫中一列或多列組合而成,其做用是提升對錶中數據的查詢速度
  • 索引的優勢是能夠提升檢索數據的速度

2.二、缺點

  • 索引的缺點是建立和維護索引須要耗費時間優化

  • 索引能夠提升查詢速度,會減慢寫入速度

  • 索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

三、索引分類

3.一、普通索引:

僅加速查詢 最基本的索引,沒有任何限制,是咱們大多數狀況下使用到的索引。

CREATE INDEX  index_name  on user_info(name)  ;

3.二、惟一索引:

與普通索引類型,不一樣的是:加速查詢 + 列值惟一(能夠有null)

CREATE UNIQUE INDEX  mail  on user_info(name)  ;

3.三、全文索引:

全文索引(FULLTEXT)僅能夠適用於MyISAM引擎的數據表;做用於CHAR、VARCHAR、TEXT數據類型的列。

3.4,組合索引:

將幾個列做爲一條索引進行檢索,使用最左匹配原則。

五、索引使用

5.一、普通索引

①、建立表的時候同事建立索引

create table healerjean (
  id   bigint(20)  NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主鍵',
  name  VARCHAR(32) NOT NULL COMMENT '姓名',
  email VARCHAR(64) NOT NULL COMMENT  '郵箱',
  message text DEFAULT  NULL COMMENT '我的信息',
  INDEX index_name (name) COMMENT '索引name'
) COMMENT  = '索引測試表';

②、在存在的表上建立索引

create index index_name on healerjean(name)

③、注意:對於建立索引時若是是blob 和 text 類型,必須指定length。

create index ix_extra on in1(message(200));
alter table employee add index emp_name (name);

⑤、刪除索引

drop index_name on healerjean;
alter TABLE users  drop index  name_index ;

⑥、查看索引
這個時候,咱們會發現其實主鍵id也是一個索引

show index from healerjean;

5.二、主鍵索引

  • 咱們通常都會提供主鍵的,默認主鍵就是索引

六、正確使用索引

6.一、對於建立的多列索引,只要查詢的條件中用到了最左邊的列,索引通常就會被使用

①、首先按 company_id,moneys 的順序建立一個複合索引,具體以下:

mysql> create index ind_sales2_companyid_moneys on sales2(company_id,moneys);
Query OK, 1000 rows affected (0.03 sec)
Records: 1000 Duplicates: 0 Warnings: 0

②、而後按 company_id 進行表查詢,具體以下:

mysql> explain select * from sales2 where company_id = 2006\G;
********* 1. row *********
id: 1
select_type: SIMPLE
table: sales2
type: ref
possible_keys: ind_sales2_companyid_moneys
208key: ind_sales2_companyid_moneys
key_len: 5
ref: const
rows: 1
Extra: Using where
1 row in set (0.00 sec)

③、能夠發現即使 where 條件中不是用的 company_id 與 moneys 的組合條件,索引仍然能用到,這就是索引的前綴特性。

④、可是若是隻按 moneys 條件查詢表,那麼索引就不會被用到,具體以下:

mysql> explain select * from sales2 where moneys = 1\G;
********* 1. row *********
id: 1
select_type: SIMPLE
table: sales2
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1000
Extra: Using where
1 row in set (0.00 sec)

6.二、對於使用 like 的查詢,後面若是是常量而且只有%號不在第一個字符,索引纔可能會被使用:

  • 能夠發現第一個例子沒有使用索引,而第二例子就可以使用索引,
  • 區別就在於「%」的位置不一樣,前者把「%」放到第一位就不能用到索引,然後者沒有放到第一位就使用了索引。
mysql> explain select * from company2 where name like '%3'\G;
********* 1. row *********
id: 1
select_type: SIMPLE
table: company2
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1000
Extra: Using where
1 row in set (0.00 sec)
mysql> explain select * from company2 where name like '3%'\G;
********* 1. row *********
id: 1
select_type: SIMPLE
table: company2
type: range
209possible_keys: ind_company2_name
key: ind_company2_name
key_len: 11
ref: NULL
rows: 103
Extra: Using where
1 row in set (0.00 sec)

6.三、若是列名,記得是列的名字,是索引,使用 column_name is null 將使用索引。

mysql> explain select * from company2 where name is null\G;
********* 1. row *********
id: 1
select_type: SIMPLE
table: company2
type: ref
possible_keys: ind_company2_name
key: ind_company2_name
key_len: 11
ref: const
rows: 1
Extra: Using where
1 row in set (0.00 sec)

6.四、若是對大的文本進行搜索,使用全文索引而不用使用 like ‘%…%’。

6.五、存在索引,可是不使用

①、若是 MySQL 估計使用索引比全表掃描更慢,則不使用索引,例如,若是列key_part1 均勻分佈在 1 和 100 之間,下列查詢中使用索引就不是很好:

SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90;

②、若是使用 MEMORY/HEAP 表而且 where 條件中不使用「=」進行索引列,那麼不會用到索引。heap 表只有在「=」的條件下才會使用索引。

③、用 or 分割開的條件,若是 or 前的條件中的列有索引,然後面的列中沒有索引,那麼涉及到的索引都不會被用到,例如:,必須or先後都有索引才能被使用,並且必須是單獨索引。

mysql> show index from sales\G;
*************************** 1. row ***************************
Table: sales
Non_unique: 1
Key_name: ind_sales_year
Seq_in_index: 1
Column_name: year
210Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
1 row in set (0.00 sec)

6.六、若是列是字符型,,傳入的是數字,則不上‘’不會使用索引

mysql> explain select * from company2 where name = 294\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: company2
type: ALL
possible_keys: ind_company2_name
key: NULL
key_len: NULL
ref: NULL
rows: 1000
Extra: Using where
1 row in set (0.00 sec)
mysql> explain select * from company2 where name = '294'\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: company2
type: ref
possible_keys: ind_company2_name
key: ind_company2_name
key_len: 23
ref: const
rows: 1
Extra: Using where
1 row in set (0.00 sec)

七、聯合索引

解釋 :能夠經過key_len的長度來判斷聯合索引使用到了那些
CREATE TABLE `d001_index` (
    `id` bigint(16) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(128) DEFAULT NULL,
    `age` bigint(20) DEFAULT '0',
    `country` varchar(50) DEFAULT NULL,
    `a` int(11) DEFAULT '0',
    `b` int(11) DEFAULT '0',
    `c` int(11) DEFAULT '0',
    `d` int(11) DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `idx_a_b_c_d` (`a`,`b`,`c`,`d`),
    KEY `idx_age` (`age`),
    KEY `idx_name` (`name`)
)
INSERT INTO `hlj-mysql`.d001_index (id, name, age, country, a, b, c, d) VALUES (1, 'zhangyj', 25, 'chine', 1, 2, 3, 4);
INSERT INTO `hlj-mysql`.d001_index (id, name, age, country, a, b, c, d) VALUES (2, 'healerjean', 24, 'china', 2, 3, 4, 5);
INSERT INTO `hlj-mysql`.d001_index (id, name, age, country, a, b, c, d) VALUES (3, 'n', 22, 'a', 2, 4, 5, 6);
INSERT INTO `hlj-mysql`.d001_index (id, name, age, country, a, b, c, d) VALUES (4, 'k', 2, 'b', 3, 5, 6, 8);
INSERT INTO `hlj-mysql`.d001_index ( name, age, country, a, b, c, d) VALUES ( 'zhangyj', 25, 'chine', 1, 2, 3, 4);
INSERT INTO `hlj-mysql`.d001_index ( name, age, country, a, b, c, d) VALUES ( 'healerjean', 24, 'china', 2, 3, 4, 5);
INSERT INTO `hlj-mysql`.d001_index ( name, age, country, a, b, c, d) VALUES ( 'n', 22, 'a', 2, 4, 5, 6);
INSERT INTO `hlj-mysql`.d001_index ( name, age, country, a, b, c, d) VALUES ( 'k', 2, 'b', 3, 5, 6, 8);

①、查詢條件爲a :用到了索引a (長度爲5)

explain  SELECT * from d001_index WHERE a = 1 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ref idx_a_b_c_d idx_a_b_c_d 5 const 1 100 NULL

②、查詢條件爲b:未用到索引

explain  SELECT * from d001_index WHERE b = 1 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL NULL NULL NULL NULL 4 25 Using where

③、查詢條件爲c:未用到索引 (d同理)

explain  SELECT * from d001_index WHERE c = 1 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL NULL NULL NULL NULL 4 25 Using where

④、查詢條件爲 b 、 c :未用到索引

explain  SELECT * from d001_index WHERE b = 1 and c = 2 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL NULL NULL NULL NULL 4 25 Using where

⑤、 查詢條件爲 a 、 b:用到了聯合索引 a 、b (長度爲10)

explain  SELECT * from d001_index WHERE a = 1 and b = 2 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ref idx_a_b_c_d idx_a_b_c_d 10 const,const 1 100 NULL

⑥、查詢條件爲 a、c :用到了聯合索引a (長度爲5)

explain  SELECT * from d001_index WHERE a = 1 and c = 3 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ref idx_a_b_c_d idx_a_b_c_d 5 const 1 25 Using index condition

⑦、查詢條件爲 a 、b、c、c:用到了聯合索引a b c d (長度爲20)

explain  SELECT * from d001_index WHERE a = 1 and b = 2 and c = 3  and d = 4 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ref idx_a_b_c_d idx_a_b_c_d 20 const,const,const,const 1 100 NULL

⑧、查詢條件爲 a or b :未用到索引

explain  SELECT * from d001_index WHERE a = 1 or b = 2;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL idx_a_b_c_d NULL NULL NULL 4 50 Using where

⑨、精確查找聯合索引總結

  • 顧名思義是最左優先,以最左邊的爲起點任何連續的索引都能匹配上
  • 多個單列索引在多條件查詢時只會生效第一個索引!因此多條件聯合查詢時最好建聯合索引!當建立(a,b,c)聯合索引時,至關於建立了(a)單列索引,(a,b)聯合索引以及(a,b,c)聯合索引想要索引生效的話,只能使用 a和a,b和a,b,c三種組合;固然,咱們上面測試過,a,c組合也能夠,但實際上只用到了a的索引,c並無用到!

  • 具體 使用 a b c 的順序無關,mysql會自動優化,可是咱們建議按照索引的順序進行查詢,並且儘可能將篩選力度大的放到前面,其實這種也不要必定是準確的,其實真正有影響的是是否用到了索引

八、單列索引

①、查詢條件爲 name:使用到了索引 name(長度爲512 = 4 * 128 + 2)

explain  SELECT * from d001_index WHERE name = 'zhangyj' ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL const idx_name idx_name 515 const 1 100 NULL

②、查詢條件爲 name 、 age :只使用了第一個 name索引(長度爲512 = 4 * 128 + 2)

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL const idx_name,idx_age idx_name 515 const 1 100 NULL

③、查詢條件爲 name or age :兩個索引都用上了 type = INDEX_MERGE 合併索引
我這裏的測試失敗了,應該是因爲個人數據表數據量比較小的緣由

九、聯合索引

9.一、聯合索引範圍查詢

  • 解釋:範圍查詢使用到第幾列,則聯合索引該列後面的字段的不能使用索引
  • 注意:不要取極端值測試,由於mysql優化器會經過索引查找的數量形成必定的影響,即便使用了索引,可是索引卻沒能生效 ,好比下的 3 變成 1 會受到影響,由於個人數據量中a最小就是 1
explain  SELECT * from d001_index WHERE a > 1  ; 
-- 沒有使用索引,由於數據均勻分佈在1 以上 (有1,可是和1比較了,因此也算在了裏面)
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL idx_a_b_c_d NULL NULL NULL 8 75 Using where

①、a > 3 使用了索引 a (長度爲 5 )

explain  SELECT * from d001_index WHERE a > 3; 
-- 使用到了索引
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL range idx_a_b_c_d idx_a_b_c_d 5 NULL 1 100 Using index condition

②、a = 1 and b > 1 :使用了聯合索引 a、b(長度爲10)

explain SELECT * from d001_index WHERE a = 1 and  b > 1 ;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL range idx_a_b_c_d idx_a_b_c_d 10 NULL 2 100 Using index condition

③、a = 5 AND b > 6 AND c = 7 :使用了聯合索引 a、b(長度爲10)

explain SELECT * from d001_index WHERE a = 5 AND b > 6 AND c = 7;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL range idx_a_b_c_d idx_a_b_c_d 10 NULL 1 12.5 Using index condition

網絡1 、能夠用到因此的狀況

A>5
A=5 AND B>6
A=5 AND B=6 AND C=7

網絡二、下面條件將不能用上組合索引查詢:

B>5 ——查詢條件不包含組合索引首列字段
B=6 AND C=7 ——查詢條件不包含組合索引首列字段

網絡三、下面條件將能用上部分組合索引查詢:

A>5 AND B=2 ——當範圍查詢使用第一列,查詢條件僅僅能使用第一列 A
A=5 AND B>6 AND C=2 ——範圍查詢使用第二列,查詢條件僅僅能使用前二列    A B

9.二、聯合查詢範圍排序

注意:表中的數據量和查詢的數據量會形成影響,因此我這裏都廣泛使用了limit 1 ,博主測試有一些結果沒有寫,測試失敗了,應該是因爲數據量的緣由,

①、order by a 使用到了聯合索引 a b c d 按理說應該只用到a纔對,這裏博主有些疑惑

explain  SELECT * from d001_index  order by  a  limit  1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL index NULL idx_a_b_c_d 20 NULL 1 100 NULL

②、order by b 未使用索引

explain  SELECT * from d001_index  order by b  limit  1;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE d001_index NULL ALL NULL NULL NULL NULL 8 100 Using filesort

網絡一、組合索引排序的各類場景

ORDER BY A ——首列排序
A=5 ORDER BY B——第一列過濾後第二列排序
ORDER BY A DESC, B DESC——注意,此時兩列以相同順序排序
A>5 ORDER BY A——數據檢索和排序都在第一列

網絡二、不能夠用到組合索引

ORDER BY B ——排序在索引的第二列
A>5 ORDER BY B ——範圍查詢在第一列,排序在第二列
A IN(1,2) ORDER BY B ——理由同上
ORDER BY A ASC, B DESC ——注意,此時兩列以不一樣順序排序
相關文章
相關標籤/搜索