建立索引

  • 表的主键、外键必须有索引;
  • 数据量超过300的表应该有索引;
  • 经常与其他表进行连接的表,在连接字段上应该建立索引;
  • 经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;
  • 索引应该建在选择性高的字段上;
  • 索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;
  • 频繁进行数据操作的表,不要建立太多的索引;

索引失效

  • 字符串不加单引号
  • 将要使用的索引列不是复合索引列表中的第一部分,则不会使用索引
  • 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null
  • 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
  • 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。
  • 应尽量避免在 where 子句中使用 or 来连接条件 (用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到),否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num=10 or num=20
  • 可以这样查询: select id from t where num=10 union all select id from t where num=20
  • in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据。如: select id from t where num in(1,2,3)
  • 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
  • 尽量避免在索引过的字符数据中,使用非打头字母%搜索。这也使得引擎无法利用索引。 见如下例子: SELECT * FROM T1 WHERE NAME LIKE ‘%L%’ SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’ SELECT * FROM T1 WHERE NAME LIKE ‘L%’
  • 即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作
  • 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描
  • 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描
  • 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引

实例

我一个表 students 表,有3个字段 ,id,name,age 我要查询 通过 name 和age,在这两个字段 是创建 联合索引?还是分别在name和age上创建 单列索引呢? 多个字段查询什么情况下用联合索引 什么时候分别创建单列索引呢?

 

1,首先要确定优化的目标,在什么样的业务场景下,表的大小等等。如果表比较小的话,可能都不需要加索引。
2,哪些字段可以建索引,一般都where、order by 或者 group by 后面的字段。
3,记录修改的时候需要维护索引,所以会有开销,要衡量建了索引之后的得与失。

学生表,可以认为name的重复度比较小,而age的重复度比较大,对于单列索引来说,比较适合建在重读度低的列上。

对于select * from students where name='张三’and age=18; 题主所说的两种情况
A. name 和 age 各自单独建立索引。
一般来说mysql会选择其中一个索引,name的可能性比较大,因为mysq会统计每个索引上的重复度,选用低重复度的字段。另外一个age的索引就不会用到,但还有维护索引的开销,所以age的索引不需要创建。

B. name和age的联合索引
这种索引的切合度最好,mysql会直接选用这个索引。但相对单独的name索引来说,维护的成本要大一些,并且索引数据占用的存储空间也要更大一些。

回过来看,有必要使用联合索引吗? 我的看法是没有必要,因为学校里可能会有重名的人,但比较少。用name就可以比较精准的找到记录,即使有重复的也比较少。

什么情况下使用联合索引比较好呢? 举一个例子,大学选认课老师,需要创建一个关系对应表,有2个字段,student_id 和 teacher_id,想要查询某个老师和某个学生是否存在师生关系。
一个学生会选几十个老师,一个老师会带几百个学生
如果只为student_id建立索引的情况下,经过索引会选出几十条记录,然后在内存中where一下,去除其余的老师。
相反如果只为teacher_id建立索引,经过索引会选出几百条记录,然后在内存中where一下,去除其余的学生。
两种情况都不是最优的,这个时候使用联合索引最合适,通过索引直接找到对应记录。

 

创建索引实例:

首先创建一个表:create table students (id int primary key,name varchar(20),age Int);

创建单个索引的语法:create index 索引名 on 表名(字段名)

索引名一般是:表名_字段名

给id创建索引:create index students _id on students (id);

创建联合索引的语法:create index 索引名 on 表名(字段名1,字段名2) 
 

给name和age创建联合索引:create index students _name_age on students (name,age)

 

 

MySQL_MySQL 联合索引详解 以及注意事项

联合索引又叫复合索引。对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。

两个或更多个列上的索引被称作复合索引。
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引 不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知 道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。
所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。
如:建立 姓名、年龄、性别的复合索引。
 

create table test(
 a int,
 b int,
 c int,
 KEY a(a,b,c)
 );

优: select * from test where a=10 and b>50
差: select * from test where a50

优: select * from test order by a
差: select * from test order by b
差: select * from test order by c

优: select * from test where a=10 order by a
优: select * from test where a=10 order by b
差: select * from test where a=10 order by c

优: select * from test where a>10 order by a
差: select * from test where a>10 order by b
差: select * from test where a>10 order by c

优: select * from test where a=10 and b=10 order by a
优: select * from test where a=10 and b=10 order by b
优: select * from test where a=10 and b=10 order by c

优: select * from test where a=10 and b=10 order by a
优: select * from test where a=10 and b>10 order by b
差: select * from test where a=10 and b>10 order by c