原文:http://www.javashuo.com/article/p-rxeunrdc-bc.htmlmysql
索引是表的目錄,在查找內容以前能夠先在目錄中查找索引位置,以此快速定位查詢數據。對於索引,會保存在額外的文件中。sql
索引是數據庫中專門用於幫助用戶快速查詢數據的一種數據結構。相似於字典中的目錄,查找字典內容時能夠根據目錄查找到數據的存放位置,而後直接獲取便可。數據庫
①、越小的數據類型一般更好:越小的數據類型一般在磁盤、內存和CPU緩存中都須要更少的空間,處理起來更快。緩存
②、簡單的數據類型更好:整型數據比起字符,處理開銷更小,由於字符串的比較更復雜。網絡
③、儘可能避免NULL:應該指定列爲NOT nuLL,在MySQL中, 含有空值的列很難進行查詢優化,由於它們使得索引、索引的統計信息以及比較運算更加複雜mysql優化
①、對於那些在查詢中不多使用或者參考的列不該該建立索引。這是因 爲,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。數據結構
②、對於那 些只有不多數據值的列也不該該增長索引。由於原本結果集合就是至關於全表查詢了,因此沒有必要。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比 例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。
③、對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多。
④、當修改性能遠遠大於檢索性能時,不該該建立索 引。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。因 此,當修改性能遠遠大於檢索性能時,不該該建立索引。
⑤、不會出如今where條件中的字段不應創建索引。性能
①、表的主鍵、外鍵必須有索引;外鍵是惟一的,並且常常會用來查詢
②、數據量超過300的表應該有索引;
③、常常與其餘表進行鏈接的表,在鏈接字段上應該創建索引;常常鏈接查詢,須要有索引
④、常常出如今Where子句中的字段,加快判斷速度,特別是大表的字段,應該創建索引,創建索引,通常用在select ……where f1 and f2 ,咱們在f1或者f2上創建索引是沒用的。只有兩個使用聯合索引纔能有用
⑤、常常用到排序的列上,由於索引已經排序。
⑥、常常用在範圍內搜索的列上建立索引,由於索引已經排序了,其指定的範圍是連續的測試
索引的缺點是建立和維護索引須要耗費時間優化
索引能夠提升查詢速度,會減慢寫入速度
索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率,由於 insert 或 update 時有可能會重建索引,因此怎樣建索引須要慎重考慮,視具體狀況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
僅加速查詢 最基本的索引,沒有任何限制,是咱們大多數狀況下使用到的索引。
CREATE INDEX index_name on user_info(name) ;
與普通索引類型,不一樣的是:加速查詢 + 列值惟一(能夠有null)
CREATE UNIQUE INDEX mail on user_info(name) ;
全文索引(FULLTEXT)僅能夠適用於MyISAM引擎的數據表;做用於CHAR、VARCHAR、TEXT數據類型的列。
將幾個列做爲一條索引進行檢索,使用最左匹配原則。
①、建立表的時候同事建立索引
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;
咱們通常都會提供主鍵的,默認主鍵就是索引
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 合併索引
我這裏的測試失敗了,應該是因爲個人數據表數據量比較小的緣由
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
注意:表中的數據量和查詢的數據量會形成影響,因此我這裏都廣泛使用了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 ——注意,此時兩列以不一樣順序排序