在 where 和 orderby 子句中使用两个单列索引
Posted
技术标签:
【中文标题】在 where 和 orderby 子句中使用两个单列索引【英文标题】:Using two single-column indexes in where and orderby clause 【发布时间】:2020-09-27 08:47:54 【问题描述】:我用谷歌搜索了很多,但找不到明确的答案
假设我们有这个查询
SELECT * WHERE user_id = x ORDER BY date_created
如果我们在 user_id 上有一个单列索引,在 date_created 上有另一个索引,优化器会使用这两个索引吗?还是只是 user_id 索引?
【问题讨论】:
运行一个解释看看。 非常感谢......所以你说它不能同时使用这两个索引。对吗? mysql 将一次对特定表使用一个索引,您可以使用复合索引,即两者的组合(user_id, date_created)
@RickJames 请删除 cmets,以及 your website 上关于 Firefox 的 FALSE 评论.... ????
@Luuk - 删除了虚假的 cmets;博客中过时的行已删除。感谢您指出。
【参考方案1】:
这是您的查询:
SELECT *
FROM mytable
WHERE user_id = 123
ORDER BY date_created
如果您有两个不同的索引,那么 MySQL 可能会使用 user_id
上的索引来应用 where
谓词(如果它认为它会加快查询速度,具体取决于数据的基数和其他因素)。它不会使用date_created
上的索引,因为它无法将满足where
谓词的中间结果集与该索引相关联。
对于这个查询,您需要一个在(user_id, date_created)
上的复合索引。数据库使用索引中的第一个键来过滤数据集:在索引B树中,匹配的行已经按日期排序,因此order by
操作变成了无操作。
我注意到您使用的是select *
;一般来说,这不是一个好的做法,也不利于性能。如果表中除了用户和日期之外还有其他列,这将强制数据库查找表以通过索引过滤和排序后带来相应的行,这可能比根本不使用索引。如果您只需要几列,请列举它们:
SELECT date_created, first_name, last_name
FROM mytable
WHERE user_id = 123
ORDER BY date_created
并且在(user_id, date_created, first_name, last_name)
上有一个索引。这是一个覆盖索引:数据库可以在索引上执行整个查询,而无需查找表本身。
【讨论】:
。 .过滤查询时,文档的该部分可能不相关。它试图避免一种称为 thrashing 的情况,即表不适合内存并且被乱序读取。在这一点上,文档应该很清楚。而且,这与select *
无关,它与索引中的键以外的 any 列有关。天哪,文档的那部分确实具有误导性。
总的来说,GMB 的回答还是不错的。但是,正如戈登指出的那样,他走向了可能不相关的方向。一些说明:必须检查列,因此*
与列列表相比,工作量没有太大差异。 重要 是否存在“未记录”的不需要的TEXT
或BLOB
列。这可能需要额外的磁盘读取来执行 SELECT *
而不是避免该列。
和“非记录”提取可能导致“颠簸”。我将“好”索引视为处理WHERE
、GROUP BY
和ORDER BY and LIMIT
的索引; “更好”的索引就是这样做并且“覆盖”的索引。但是,“覆盖”通常是不可能的(因为TEXT
)或不实用(“太多”列)。
@GordonLinoff:我从我的回答中删除了该文档引用,因为它确实具有误导性(对我来说也是如此!)。
@RickJames:我打算在select *
讨论中介绍覆盖 概念。我稍微编辑了我的答案,以(希望)让它更清晰一些。以上是关于在 where 和 orderby 子句中使用两个单列索引的主要内容,如果未能解决你的问题,请参考以下文章
iOS - Firestore 复合索引中的索引上的多个 orderBy 和 where 子句