這裏所談論只針對B-Tree類型索引,也是MySQL用的最多最普通的索引。建立索引的時候是按照字面量的順序建立的,這個要特別注意。在B-Tree類型索引中,索引順序是相當重要的。mysql
索引要小而美sql
單列索引數據庫
前綴索引函數
多列索引性能
選擇合適的索引順序.net
覆蓋索引code
使用索引掃描來排序orm
參照前面寫的文章造數據blog
http://blog.csdn.net/csujiangyu/article/details/51096978排序
索引結構以下
mysql> show index from user; +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | user | 0 | PRIMARY | 1 | id | A | 92123632 | NULL | NULL | | BTREE | | | | user | 1 | idx_last_first_name_age | 1 | last_name | A | 363474 | NULL | NULL | YES | BTREE | | | | user | 1 | idx_last_first_name_age | 2 | first_name | A | 92123840 | NULL | NULL | YES | BTREE | | | | user | 1 | idx_last_first_name_age | 3 | age | A | 87360984 | NULL | NULL | YES | BTREE | | | | user | 1 | idx_phone | 1 | phone | A | 92123840 | NULL | NULL | YES | BTREE | | | | user | 1 | idx_create_time | 1 | create_time | A | 88503 | NULL | NULL | YES | BTREE | | | +-------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 6 rows in set (0.00 sec)
user表一共有4個索引,包括一個主鍵id,2個單列索引(phone, create_time), 1個多列索引(last_name+first_name+age)
主要關注以下:
type:訪問類型,性能從差到好爲:
ALL -> index -> range -> ref -> eq_ref -> const,system -> NULL
index:使用的索引
這是最簡單的方式
mysql> explain SELECT * from user where phone = '13901986429'; +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | idx_phone | idx_phone | 14 | const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.01 sec)
從type能夠得知訪問類型ref,使用索引key爲idx_phone。
mysql> explain SELECT * FROM user where last_name='last_name_110' and first_name='first_name_115' and sex='F'; +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ref | idx_last_first_name_age | idx_last_first_name_age | 96 | const,const | 1 | 10.00 | Using where | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
若是是單列索引,能夠匹配列的最左前綴
mysql> explain SELECT * from user where phone like '139019864%'; +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | user | NULL | range | idx_phone | idx_phone | 14 | NULL | 100 | 100.00 | Using index condition | +----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.01 sec)
若是是多列索引,能夠從左開始組合索引
mysql> explain SELECT * FROM user where last_name='last_name_110' and first_name='first_name_115'; +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------+ | 1 | SIMPLE | user | NULL | ref | idx_last_first_name_age | idx_last_first_name_age | 96 | const,const | 1 | 100.00 | NULL | +----+-------------+-------+------------+------+-------------------------+-------------------------+---------+-------------+------+----------+-------+ 1 row in set, 1 warning (0.01 sec)
使用between
mysql> explain select * from user where id between 1 and 10; +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 10 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
使用in
mysql> explain select * from user where id in (1, 2, 3); +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 3 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.01 sec)
使用or
mysql> explain select * from user where id=1 or id=10; +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 2 | 100.00 | Using where | +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
Extra字段爲Using index,能夠看出返回數據只須要查索引便可,不須要回表查其餘字段數據。
mysql> explain select phone from user where phone='13900123456'; +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ | 1 | SIMPLE | user | NULL | ref | idx_phone | idx_phone | 14 | const | 1 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
從type爲ALL能夠看出進行了全表掃描。
phone是索引列,格式爲’%XXX’不能是使用索引
mysql> explain SELECT * from user where phone like '%39019864%'; +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 9698255 | 11.11 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
last_name + first_name + sex聯合組成了多列索引,採用最左匹配, 只有last_name,last_name + first_name,last_name + first_name + sex才能使用索引。
mysql> explain SELECT * FROM user where first_name='first_name_115' and sex='F'; +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 9698255 | 1.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
mysql> explain SELECT * FROM user where left(phone, 11) = '13900123456'; +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 9698255 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
mysql> explain select * from user where id + 1 = 2; +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 92123838 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
mysql> explain select * from user where id=1 or age=10; +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | PRIMARY | NULL | NULL | NULL | 92123838 | 10.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+----------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
-- 查看example數據庫總體大小 SELECT CONCAT(table_schema,'.',table_name) AS 'Table Name', CONCAT(ROUND(table_rows/1000000,4),'M') AS 'Number of Rows', CONCAT(ROUND(data_length/(1024*1024*1024),4),'G') AS 'Data Size', CONCAT(ROUND(index_length/(1024*1024*1024),4),'G') AS 'Index Size', CONCAT(ROUND((data_length+index_length)/(1024*1024*1024),4),'G') AS'Total'FROM information_schema.TABLES WHERE table_schema = 'example';
從圖能夠看出,1億條數據索引佔用了9.69G,數據佔用了10G,總共佔用了將近20G。索引佔用空間幾乎和數據大小同樣,所以咱們須要慎用索引,在必要的狀況下才使用,索引要小而美。