【问题标题】:At what execution level will MySQL utilize the index for ORDER BY?MySQL 在什么执行级别将索引用于 ORDER BY?
【发布时间】:2014-12-21 01:03:25
【问题描述】:

我想了解 MySQL 在使用 ORDER BY 时会在什么时间点使用索引列。

例如查询

SELECT * FROM A
INNER JOIN B ON B.id = A.id
WHERE A.status = 1 AND A.name = 'Mike' AND A.created_on BETWEEN '2014-10-01 00:00:00' AND NOW()
ORDER BY A.accessed_on DESC

据我所知,上述查询的一个好的索引是表 A (id, status, name created_on, accessed_on) 上的索引和 B.id 上的另一个索引。

我也明白 SQL 的执行顺序如下。但我不确定订单选择和订单是如何工作的。

  1. FROM 子句
  2. WHERE 子句
  3. GROUP BY 子句
  4. HAVING 子句
  5. SELECT 子句
  6. ORDER BY 子句

问题

id 列开始索引会更好,还是在这种情况下无关紧要,因为WHERE 在JOIN 之前首先执行?还是应该是

第二个问题accessed_on列应该在索引组合的开头,结尾还是中间?还是应该将id 列放在WHERE 子句中的所有列之后?

感谢详细解答,让我了解 MySQL/SQL 的执行级别

更新

我在表 A 和 B 中添加了几百万条记录,然后我添加了多个索引来查看哪个是最佳索引。但是,MySQL 似乎喜欢索引 id_2 (ie. (status, name, created_on, id, accessed_on))

它似乎正在应用 where 并且它会发现它需要并索引状态、名称、created_on 然后它会使用 INNER JOIN 并且它将使用 id 索引,然后是前 3 个。最后,它将查找accessed_on 作为最后一列。所以索引(status, name, created_on, id, accessed_on) 符合相同的执行顺序

这是表格结构

CREATE TABLE `a` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `status` int(2) NOT NULL,
  `name` varchar(255) NOT NULL,
  `created_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `accessed_on` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `status` (`status`,`name`),
  KEY `status_2` (`status`,`name`,`created_on`),
  KEY `status_3` (`status`,`name`,`created_on`,`accessed_on`),
  KEY `status_4` (`status`,`name`,`accessed_on`),
  KEY `id` (`id`,`status`,`name`,`created_on`,`accessed_on`),
  KEY `id_2` (`status`,`name`,`created_on`,`id`,`accessed_on`)
) ENGINE=InnoDB AUTO_INCREMENT=3135750 DEFAULT CHARSET=utf8


CREATE TABLE `b` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3012644 DEFAULT CHARSET=utf8

【问题讨论】:

  • 您可以使用EXPLAIN SELECT * FROM A ...查看哪些键是正确的等等。

标签: mysql sql


【解决方案1】:

此查询的最佳索引是:A(status, name, created_on)B(id)。这些索引将满足where 子句并使用索引来连接B

此索引不会用于排序。使用任何索引进行排序有两个主要障碍。第一个是加入。第二个是created_on 上的不等式。一些数据库可能会在A(status, name, accessed_on) 上使用索引,但我认为 MySQL 还不够聪明。

您不希望 id 作为索引中的第一列。这排除了使用索引过滤A,因为id 用于join 而不是where

【讨论】:

  • 所以你从索引中取出了 id 列。由于连接必须在没有索引的情况下完成,这会减慢查询速度吗?或者在这种情况下它会使用一个索引来表示同一个表中的连接吗?
  • 请检查我更新的问题。 MySQL 似乎认为以下顺序的索引最适合(status, name, created_on, id, accessed_on)
  • @Mike 。 . .我认为就是这样,它具有索引中大部分查询所需的所有列。该索引涵盖除select * 之外的所有内容。如果你使用这个索引,它是否仍然对查询进行文件排序?
  • 是的(使用 where;使用索引;使用文件排序)
  • @Mike 。 . .我怀疑会是这样。推荐的索引和我建议的索引可能差别很小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-29
  • 2022-01-17
  • 2017-01-20
  • 2011-09-29
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多