Choosing the best indexes for MySQL query optimization翻译:为MySQL查询选择最佳索引

这是EverSQL上两篇文章的整合,分别是:
Choosing the best indexes for MySQL query optimization
https://www.eversql.com/choosing-the-best-indexes-for-mysql-query-optimization/
How to find unused indexes in a MySQL database?
https://www.eversql.com/how-to-find-unused-indexes-in-a-mysql-database/

我们应该为SQL查询创建哪些索引?

一般来说,MySQL只能为查询中的每个表使用一个索引。因此为每个查询创建多于一个的索引是没有意义的。同一个索引最好可以适用于尽量多个查询,这样可以减少数据增删改时数据库的压力。

  1. 最重要的是WHERE和JOIN子句中的相等条件。大部分情况向下,像name = ‘John’这种条件,可以使数据库过滤掉大部分行,只扫描一小部分数据并返回结果。因此我们应该在这些列上加索引。
  2. WHERE子句中的范围条件,但只能在其中一个上加索引,因为MySQL不能同时使用那么多。
  3. 如果查询没有范围条件,可以添加 GROUP BY 子句中的列。
  4. 如果查询没有 GROUP BY 子句,也可以创建一个包含ORDER BY子句列的索引。
  5. 可以创建一个独立的索引来保存 ORDER BY 子句的列,但索引需要包含 ORDER BY 子句中的所有列,它们应该全部在 ORDER BY 子句中用相同的顺序(ASC / DESC)指定。但这不代表数据库优化器一定会使用这个索引,但值得一试。
  6. 如果索引不是太大(一般5-7个就算大了),也可以将SELECT字句中的列加入索引。创建覆盖索引允许数据库不仅使用索引进行过滤,而且还可以直接从索引中获取SELECT子句所需的信息,从而节省了宝贵的I/O操作。

看一个例子:

SELECT
    id, first_name, last_name, age
FROM
    employees
WHERE
    first_name = 'John'
        AND last_name = 'Brack'
        AND age > 25
ORDER BY age ASC;

在这个查询中,首先我们会添加等于判断中的first_name和last_name列。然后添加范围判断中的age列。不需要添加ORDER BY子句中的列,因为age列已经在索引中了。然后将SELECT子句中的id添加到索引,使之更完备。
所以根据查询特性,我们应该添加索引:

employees (first_name, last_name, age, id)

添加索引或者写SQL时不要做什么?

下面整理了常见的查询错误和索引添加错误。

  1. 在一个表中分别为不同列添加单独的索引。
    大部分时候,MySQL不会在一个查询中为一个表使用多个索引。因此在一个表中创建单独的索引,数据库只能使用索引执行其中一个搜索操作,其余的将显着减慢,因为数据库不能使用索引来执行它们。我们建议使用复合索引而非单一索引。
  2. 过滤条件中的OR操作。
    SELECT
        a, b
    FROM
        tbl
    WHERE
        a = 3 OR b = 8;
    
    大部分时候,MySQL无法在OR条件中使用索引,所以上面的查询无法使用索引执行。因此我们建议避免使用OR条件,而是先分成两部分查询,再使用UNION DISTINCT(如果两部分查询没有重复项,那么使用UNION ALL会更好)结合起来。
  3. 索引中列的顺序很重要
    比如我的手机通讯录中按名字排列,需要统计有多少名叫John的人,那么只需要将页面导航到包含以John开头的地方,并从那里开始计数。如果通讯录按姓排序,此时再统计叫John的人,那就困难许多了。数据库也在这种情况下摸不着头脑。
    下面看一个SQL查询,模拟MySQL优化器的行为:
    SELECT
        first_name, last_name
    FROM
        contacts
    WHERE
        first_name = 'John';
    
    这里索引contacts (first_name, last_name)是比较理想的,以为这个索引第一个是过滤条件中的列,并且包含查询子句中的列。但是索引contacts (last_name, first_name)则没什么用处,因为我们的过滤条件是索引中的第二列而不是第一列。这个例子说明索引中列的顺序非常重要。
  4. 添加冗余索引
    在尝试优化SQL查询时,索引非常出色,可以显着提高性能。但其实索引也会影响效率。因为每个索引都需要在数据库发生变化时进行更新和同步。数据库每执行一次增删改的操作,所有相关索引都要更新。这会耗费一定的时间,对于大型表或者索引则更甚。因此不要创建不确定是否需要的索引。强烈建议偶尔分析一下数据库,查找一下冗余的索引并将其移除。

如何查找无用的索引?

从MySQL 5.6开始,数据库会保存索引的使用数据作为PERFORMANCE SCHEMA的一部分。视图schema_unused_indexes中可以查到没被使用过的索引。但这里面的数据是从MySQL重启后开始记录的,所以需要MySQL运行一段时间再检索比较靠谱。
运行:

select * from sys.schema_unused_indexes;

结果:

object_schema object_name index_name
(N/A) (N/A) (N/A)

删除索引:

DROP INDEX `index_name` on table

猜你喜欢

转载自blog.csdn.net/weixin_41657493/article/details/92759496
今日推荐