原文: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 ——注意,此时两列以不一样顺序排序