1. 创建索引

对于查询占主要的应用场景,索引显得尤为重要。很多时候性能问题的根源很简单:我们忘了添加索引,或者没有添加更为有效的索引。如果不加索引,哪怕只是查找一条特定的数据,数据库也可能进行一次全表扫描。如果表的数据量很大而符合条件的结果很少,不加索引会引起致命的性能下降。

但是,并非所有情况都必须建索引。例如“性别”列可能只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引

2. 复合索引

假设有如下查询语句:

SELECT * FROM users WHERE area = 'beijing' AND age = 22;

如果在 areaage 上分别创建单个索引,由于 MySQL 查询每次通常只能使用一个索引,虽然这样相比不做索引时的全表扫描提高了很多效率,但如果在 areaage 两列上创建复合索引,将带来更高的效率。

如果我们创建了 (area, age, salary) 的复合索引,那么其实相当于创建了 (area, age, salary)(area, age)(area) 三个索引,这被称为最佳左前缀特性。因此,我们在创建复合索引时,应该将最常用作限制条件的列放在最左边,依次递减。

3. 避免字段默认值为 NULL

在数据库设计时,尽量不要让字段的默认值为 NULL。只要列中包含 NULL 值,可能会对索引的有效性产生影响;在复合索引中,只要有一列含有 NULL 值,那么这一列对于此复合索引可能就是无效的。

注意:不同存储引擎对 NULL 值的索引处理方式有所不同,但为了避免查询逻辑复杂化及潜在的性能损耗,建议尽量定义为 NOT NULL

4. 使用短索引

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

5. 排序与索引

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

6. LIKE 语句优化

一般情况下不鼓励使用 LIKE 操作,如果非使用不可,如何使用也是一个问题。

  • LIKE '%aaa%':不会使用索引。
  • LIKE 'aaa%':可以使用索引。

7. 避免对列进行运算

以下写法将在每个行上进行运算,这将导致索引失效而进行全表扫描:

SELECT * FROM users WHERE YEAR(adddate) < 2007;

我们可以改成如下写法,以利用索引:

SELECT * FROM users WHERE adddate < '2007-01-01';

8. 避免使用 NOT IN 和 <>

NOT IN<> 操作通常都不会使用索引,将进行全表扫描。

  • NOT IN 可以用 NOT EXISTS 代替。
  • id <> 3 则可使用 id > 3 OR id < 3 来代替。
说明:本文基于 MySQL 通用优化原则整理。部分细节(如 NULL 值索引行为、索引合并特性等)可能因 MySQL 版本(5.7/8.0)及存储引擎(InnoDB/MyISAM)的不同而有所差异,实际生产环境请结合具体版本测试验证。