几乎所有的面试都提到了Mysql的优化问题,所以以后要多多学习数据库的优化知识了。下面仅仅考虑在索引方面的优化,此处的索引包括多列索引和联合索引!下边是在网上找到的一些资料,保留下来备用吧。

一  什么是索引

MySQL中,索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引按照实现的方式有不同的种类,像B-Tree索引,hash索引,空间数据索引和全文索引等。下面分析B-Tree索引。

1)  索引定义

普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。

主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。

索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。

索引可以极大的提高数据的查询速度,但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件。

2)   创建索引

在where,order by,group by中频繁出现,且数据分布比较离散的列适合创建索引。

很多时候一些简单的性能问题是因为忘了添加索引而造成的,或者说没有添加更为有效的索引导致的。如果不加索引,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能问题——慢得如蜗牛。但是也不是什么情况都非得建索引不可,值可以枚举的字段就无需创建索引,比如性别,因为只有男,女,未知等几种,数据不够离散,建索引显然是画蛇添足。

频繁修改的列不适合创建索引。索引基于B+树实现,修改数据时,需要修改对应的索引。因此不适合创建索引

3)   不使用NOT IN操作

NOT IN操作都不会使用索引将进行全表扫描。NOT IN可以由NOT EXISTS代替。

4)   索引不可包含有NULL值的列

这个问题有点复杂,尽量回避。

null列是可以用到索引的,不管是单列索引还是联合索引,但是,不建议这么操作,最好限制not null,并设置一个默认值,比如0和''空字符串等。官方文档中介绍到,如果某列字段中包含null,确实是可以使用索引的,地址:https://dev.mysql.com/doc/refman/5.7/en/is-null-optimization.html。

5)   使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

6) 排序的索引问题

mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此,在数据库默认排序已经符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

7)   like语句操作

一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

8) 不要在列上进行运算

select * from users where YEAR(adddate)<2007;

此SQL将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成 select * from users where adddate

下面综述哪些操作符可以命中索引,哪些不可以。

能命中索引: ,>=,BETWEEN,IN, like 'xx%';

不能命中: <>,not in ,!=,like '%xx'。

二  多列索引

多个单列索引在多条件查询时只会生效距离where最近的那索引!所以多条件联合查询时最好建联合索引!假设users中age和area分别创建了索引,则如下SQL中,例1只有area走索引,例2只有age走索引。

例1 select * from users where area=’beijing’ and age=22;

例2 select * from users where age=22 and area=’beijing’;

但是,如果把and换为or,则两个索引都走了。

三  复合索引

复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏排序,然后按名字对有相同姓氏的人排序。如果知道姓,电话簿将非常有用;如果知道姓和名,电话簿则更为有用,但如果只知道名,电话簿几乎不起作用了。所以说创建复合索引时,应该仔细考虑列的顺序。

如果在表users创建了复合索引(area, age, salary),那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最左前缀原则,顾名思义,就是最左优先。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

另外,(area, salary)中,只有area走索引。

复合索引是常考的点,小伙伴们,记牢呦。 下面从网上摘抄了一个表格,信息量比较大,仅供参考!以 index(a, b, c) 为例:

WHERE语句

发挥作用的索引

记忆方法(以三块板子过河记忆,顺序很重要)

WHERE a=3

a

只走了a板子

WHERE a=3 AND b=5

a、b

只走了ab两块板子

WHERE a=3 AND b=4 AND c=5(不论顺序)

a、b、c

走了所有的板子

WHERE b=4 AND c=5 或 WHERE b=4

因为a板子没走,所以衔接不上b和c板子

WHERE a=3 AND c=5

a

只走a,没走b就衔接不上c

WHERE a=3 AND b>10 AND c=7

a、b

走完了a,但b走了一半,与c衔接不上了

WHERE a=3 AND b LIKE '***%' AND c=7

a、b

走完了a,b走了前一半,与c衔接不上了

WHERE a=3 AND b LIKE '%***' AND c=7

a

走完了a,b走了后一半,但b前半段与a衔接不上了,走也是白走

WHERE a=3 AND c>10 AND b=4

a、b、c

走完了a和b,c只走了一半

注意:1)例子里都是 WHERE 语句,但 ORDER BY/GROUP BY 等都会用到索引,分析与上面一样

2)MySQL会一直向右匹配,直到查询中遇到范围查询(、between、like和%)等就停止匹配后面的查询条件

联合索引比对每个列分别建索引更有优势,因为索引建立得越多就越占磁盘空间,在更新或者写入数据的时候需要进行IO操作,从而导致速度下降。另外建立多列索引时,顺序也是需要注意的,应该将严格的索引放在前面,这样筛选的力度会更大,效率更高。