日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL索引知识总结

發布時間:2025/3/21 数据库 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL索引知识总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對MySQL索引知識的總結筆記。

普通索引

索引是一種數據結構,主要用于性能的提高。

比如我們有一個表t_users,有4個字段:

1234567 create table t_users ( id bigint(20) not null auto_increment, name varchar(255) not null,age bigint(20) not null, num bigint(20) not null,primary key (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

往這個表中插入100w條數據,name字段是format-1到100w,age字段也是1-100w,num字段是個隨機的10以內的數字。然后執行sql語句進行查詢:

1234567 mysql> select * from t_users where name = 'format-500000';+--------+---------------+--------+-----+| id | name | age | num |+--------+---------------+--------+-----+| 500000 | format-500000 | 500000 | 38 |+--------+---------------+--------+-----+1 row in set (0.47 sec)

explain一下這條語句:

123456 mysql> explain select * from t_users where name = 'format-500000';+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

發現查詢了996677條數據,進行了全表的掃描。

我們給name字段加上索引:

1 mysql> create index IDX_FOR_NAME on t_users(name);

再次執行sql語句:

1234567 mysql> select * from t_users where name = 'format-500000';+--------+---------------+--------+-----+| id | name | age | num |+--------+---------------+--------+-----+| 500000 | format-500000 | 500000 | 38 |+--------+---------------+--------+-----+1 row in set (0.00 sec)

explain一下:

1234567 mysql> explain select * from t_users where name = 'format-500000';+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+| 1 | SIMPLE | t_users | ref | IDX_FOR_NAME | IDX_FOR_NAME | 767 | const | 1 | Using index condition |+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+1 row in set (0.00 sec)

只查詢了1條數據,因為我們加了btree索引,可以快速定位到具體的值。

接下來我們查詢num字段:

12345678910 mysql> select * from t_users where num = 66;+--------+---------------+--------+-----+....| 965109 | format-965109 | 965109 | 66 || 965172 | format-965172 | 965172 | 66 || 965182 | format-965182 | 965182 | 66 || 965213 | format-965213 | 965213 | 66 |....+--------+---------------+--------+-----+10029 rows in set (0.30 sec)

由于num字段也是沒有加索引的,查詢的時候也進行全表的掃描,查詢耗時。接下來我們給num字段加上索引。

1 mysql> create index IDX_FOR_NUM on t_users(num);

然后進行查詢:

12345678910 mysql> select * from t_users where num = 5;+--------+---------------+--------+-----+....| 965109 | format-965109 | 965109 | 5 || 965172 | format-965172 | 965172 | 5 || 965182 | format-965182 | 965182 | 5 || 965213 | format-965213 | 965213 | 5 |....+--------+---------------+--------+-----+10029 rows in set (0.04 sec)

explain一下:

123456 mysql> explain select * from t_users where num = 5;+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+| 1 | SIMPLE | t_users | ref | IDX_FOR_NUM | IDX_FOR_NUM | 8 | const | 206712 | NULL |+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+

雖然我們在num字段上加了索引,但是由于num值在這100w條數據中有很多重復的數據,這個時候索引對查詢速度的提高就沒有那么明顯了。

因為不論是hash類型的索引還是btree類型的索引,他們對于重復的數據的查詢并沒有提高多少。相反,由于添加了索引,導致數據寫入性能變差,而查詢性能又沒有增強多少。所以說不能盲目地添加索引。

復合索引

復合索引也叫聯合索引,表示索引建立在多個列上。

我們刪除t_users上的索引,然后創建一個復合索引。

1234 mysql> drop index IDX_FOR_NUM on t_users;mysql> drop index IDX_FOR_NAME on t_users;mysql> create index INDEX_FOR_NAME_AGE on t_users(name, age);

復合索引支持最左原則,也就是說INDEX_FOR_NAME_AGE索引支持name字段的查找,支持name,age字段的查找,但是不支持age,name字段的查找以及age字段的查找。

1234567891011121314151617181920 mysql> explain select * from t_users where name = 'format-100000';+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 767 | const | 1 | Using index condition |+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+mysql> explain select * from t_users where name = 'format-100000' and age = 100000;+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 775 | const,const | 1 | Using index condition |+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+mysql> explain select * from t_users where age = 100000;+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

使用age,name字段查找:

123456 mysql> explain select * from t_users where age = 100000 and name = 'format-100000';+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 775 | const,const | 1 | Using index condition |+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+

我們發現使用age,name字段的查找使用了復合索引,這是因為MySQL內部有個查詢優化器幫我們進行了優化。

索引的生效

索引創建之后,查詢的過程并不一定會使用索引。整理如下(t_users表中name和num字段都有單獨的索引):

1.當使用索引查詢比全表掃描更慢。比如下面這句sql中num字段的值分布在1-10之間

123456 mysql> explain select * from t_users where num > 1 and num < 8;+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | IDX_ON_NUM | NULL | NULL | NULL | 996504 | Using where |+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+

2.使用or進行查詢,并且or左右兩邊的列有不存在索引的列

123456 mysql> explain select * from t_users where name = 'format-4000' or age = 50;+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | IDX_FOR_NAME | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

or兩邊的列都有索引:

123456 mysql> explain select * from t_users where name = 'format-4000' or num = 50;+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+| 1 | SIMPLE | t_users | index_merge | IDX_ON_NUM,IDX_FOR_NAME | IDX_FOR_NAME,IDX_ON_NUM | 767,8 | NULL | 2 | Using union(IDX_FOR_NAME,IDX_ON_NUM); Using where |+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+

3.使用like,并以 % 開頭

12345678910111213 mysql> explain select * from t_users where name like "%format-200";+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+mysql> explain select * from t_users where name like "%format-200%";+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

以 % 結尾的查詢會使用索引:

123456 mysql> explain select * from t_users where name like "format-200%";+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+| 1 | SIMPLE | t_users | range | IDX_FOR_NAME | IDX_FOR_NAME | 767 | NULL | 1110 | Using index condition |+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+

4.復合索引

不是復合索引的最左字段(t_users表有(name,age)復合索引)。

123456 mysql> explain select * from t_users where age = 100000;+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

5.對varchar類型的字段進行查詢的時候,沒有加上引號

12345678910111213 mysql> explain select * from t_users where name = 111;+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+| 1 | SIMPLE | t_users | ALL | IDX_FOR_NAME | NULL | NULL | NULL | 996677 | Using where |+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+mysql> explain select * from t_users where name = "111";+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+| 1 | SIMPLE | t_users | ref | IDX_FOR_NAME | IDX_FOR_NAME | 767 | const | 1 | Using index condition |+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+

hash索引和btree索引的區別

  • hash索引不能使用范圍查詢,只能使用一些比如 “=”, “<>”, “in”查詢。因為hash索引會計算索引列的hash值,計算出后的hash值經過了hash算法與原先的值完全不一樣,只能進行等值的過濾,不能基于范圍的過濾
  • hash索引遇到大量hash值相同的情況下,性能比btree要差
  • hash索引并不一定一次可以定位到數據。因為基于索引列計算出的hash值會有重復,重復的話需要掃描hash表進行比較
  • 由于hash索引中存放的是經過hash計算之后的hash值,而且hash值的大小關系并不一定和hash運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算
  • 對于組合索引,hash索引在計算hash值的時候是組合索引鍵合并后再一起計算hash值,而不是單獨計算hash值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,hash索引也無法被利用
  • InnoDB和MyISAM引擎不支持hash索引
  • 本文作者:Format
    原文鏈接: http://fangjian0423.github.io/2017/07/05/mysql-index-summary/

    總結

    以上是生活随笔為你收集整理的MySQL索引知识总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。