【问题标题】:Optimizing MySql query (IN) to avoid using “Using filesort”优化 MySql 查询(IN)以避免使用“Using filesort”
【发布时间】:2014-07-17 15:41:46
【问题描述】:

我需要您的帮助来优化查询以避免使用“使用文件排序”。查询是:

SELECT name
FROM actor
WHERE actor_id IN (3333,1452,2587,3003,3044,3524,3700,7087,7088)
ORDER BY name ASC

解释结果:

1   SIMPLE  actor   range   PRIMARY PRIMARY 2       9   Using where; Using filesort

================================================ ==============

SQL 小提琴 http://sqlfiddle.com/#!2/50c4d/1/0

表:

CREATE TABLE `actor` (
`actor_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,  
PRIMARY KEY (`actor_id`),
UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB;

样本数据:

INSERT INTO `actor` VALUES (7087, 'Brill');
INSERT INTO `actor` VALUES (3333, 'Rey');
INSERT INTO `actor` VALUES (7088, 'Graves');
INSERT INTO `actor` VALUES (1452, 'Phoenix');
INSERT INTO `actor` VALUES (2587, 'Segal');
INSERT INTO `actor` VALUES (3003, 'Taylor');
INSERT INTO `actor` VALUES (3044, 'Daniels');
INSERT INTO `actor` VALUES (3524, 'Michaels');
INSERT INTO `actor` VALUES (3700, 'Tryme');

索引:

ADD INDEX idx_test (actor_id, name) -> EXTRA: Using where; Using index; Using filesort

【问题讨论】:

  • 那张表中还有更多数据吗?仅使用您提供的数据设置该表时,我只会得到“使用位置;使用索引”
  • 是的,我有更多字段,例如 url、thumb、status……但总是额外的:使用文件排序……(有索引,没有索引)……我不知道为什么……

标签: mysql performance optimization query-optimization filesort


【解决方案1】:

我总是很困惑,为什么人们如此执着于避免FILESORT!?!

您正在请求基于actor_id 的表的子集。服务器看到actor_id 字段上有一个索引(PK 或idx_test),将通过索引查找相关记录并返回它们。现在,此外,您还希望输出按给定顺序排列。如果订单是ORDER BY actor_id,那么就可以利用获取的记录已经在索引(或PK)中的该字段上预先排序的事实。因此,不需要重新排序,并且可以“按原样”返回输出 (**)。

但是,您不希望它们按actor_id 的顺序排列,您希望它们按name 的顺序排列。因此,机器会按照您的要求执行并按name 对记录进行排序,然后再将它们返回给您。我怀疑对这么小的列表进行排序会占用大量资源或时间。

PS:我认为索引在这里对您没有多大帮助,实际上它(非常糟糕!)复制了(集群)PK。我可以看到这样一个索引的唯一(潜在)好处是,如果实际表更宽,那么它将作为这个查询的覆盖索引,减少 I/O (++)。请注意,这也意味着您在查询时不能要求任何其他字段。

(**:我敢肯定它在内部有点复杂)

(++:SELECT 的 I/O 更少,IUD 需要更多的 I/O)

【讨论】:

  • +1,尤其是第一句话。人们一心想避免它,因为完全不知道发生了什么,他们得出了错误的结论。
  • @deroby 谢谢你的解释,我认为“使用文件排序”或“使用临时”总是会减慢查询速度的坏事,所以我想办法避免它(actor表有数千记录和更多列)
  • 不用担心,“数千行”对于任何自尊的 RDBMS 来说都是轻而易举的事。
【解决方案2】:

您可以为 范围谓词 IN(...) 使用索引。或者您可以使用索引来消除文件排序。

您不能让两个操作都使用索引,至少当谓词中的列与排序顺序中的列不同时不会。

你创建了这个索引:

ADD INDEX idx_test (actor_id, name) -> EXTRA: Using where; Using index; Using filesort

这有助于找到匹配的 actor_id 值。复合索引包含您想要的 name 列。但是你希望它按name 排序。索引不是按name排序的,而是先按actor_id排序,再按name排序。

这是一个类比来解释为什么这不起作用:

假设我让你查看电话簿并找到那些 姓氏是富兰克林、汉密尔顿、杰斐逊、华盛顿。然后排序 他们的名字。电话簿按姓氏排序,然后按 名。所以你可以快速找到姓氏,但第一个 姓名被返回本杰明、亚历山大、托马斯、乔治——没有任何 明智的秩序。

要按名字对它们进行排序,您必须收集结果,然后 手动对它们进行排序。他们在电话中被分类的事实 书没用。

【讨论】:

    猜你喜欢
    • 2011-06-14
    • 2012-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多