Mysql - 为什么FileSort需要比实际获取更长的时间?

时间:2014-08-18 13:09:34

标签: mysql database-performance

我的Mysql数据库上运行了一个SQL查询。 我有一张1.5M记录的表格。我试图根据项目'来获取最后创建的50个项目。创造者。

以下是查询:

SELECT *
FROM `items`
WHERE `items`.`owner_id`
  IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY `items`.`id`
  DESC LIMIT 50

查询使用owner_id索引,这是有道理的。对? 显然,使用此索引需要将近3秒,而使用主索引需要100毫秒。

在完成解释时,我会看到以下内容:

1   SIMPLE  items   range   idx_owner   idx_owner   4   NULL    56  Using index condition; Using filesort

但是当我运行以下查询时:

SELECT *
FROM `items` FORCE INDEX(PRIMARY)
WHERE `items`.`owner_id`
  IN (1, 2, 3, 4, 5, 6, 7, 8)
ORDER BY `items`.`id`
  DESC LIMIT 50

我得到以下解释:

1   SIMPLE  items   index   NULL    PRIMARY 4   NULL    50  Using where

这意味着我只是摆脱了文件排序,虽然我在where子句上丢失了索引。

查询似乎返回15,000条记录(由于输入),然后对它们进行排序并选择最后50条记录。 至于我的问题 - 如何排序15,000条记录的效率低于扫描1.5M表并搜索15,000条记录?排序不应该是一项艰巨的任务,而搜索则更困难(没有索引!)我错过了什么?

附加 - 表的索引:

items   0   PRIMARY 1   id  A   1444298 NULL    NULL        BTREE       
items   1   items_a951d5d6  1   slug    A   288859  767 NULL        BTREE       
items   1   category_id_refs_id_3b77a81e    1   category_id A   34  NULL    NULL    YES BTREE       
items   1   origin_id_refs_id_99b3fd12  1   origin_id   A   2   NULL    NULL    YES BTREE       
items   1   parent_id_refs_id_99b3fd12  1   parent_id   A   6   NULL    NULL    YES BTREE       
items   1   name    1   name    A   1444298 NULL    NULL        BTREE       
items   1   idx_owner   1   owner_id    A   722149  NULL    NULL        BTREE       

谢谢!

1 个答案:

答案 0 :(得分:2)

排序数千个完整的信息行并不像你想象的那么便宜。另请注意,filesort并不一定意味着文件系统中文件的排序。这意味着需要对派生表进行排序。

您正在查看的查询可以按如下方式进行重构,结果很可能会更好。

SELECT i.*
  FROM items AS i
  JOIN (
        SELECT id
          FROM items
         WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
         ORDER BY id DESC
         LIMIT 50
       ) AS j ON i.id = j.id
 ORDER BY i.id DESC

这是因为您的原始查询包含SELECT *。为了满足该查询,MySQL必须对表的所有列进行洗牌。此重构中的子查询只是提供了您想要的五十个id值。它仍然需要对它们进行排序,但排序一堆整数比排序一堆行更快。

        SELECT id
          FROM items
         WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)
         ORDER BY id DESC
         LIMIT 50

外部查询检索这五十个ID中的每一个的整行,这应该相对较快。

这里需要注意的事情。

WHERE owner_id BETWEEN 1 AND 8 
MySQL将比

更容易满足

WHERE owner_id IN (1, 2, 3, 4, 5, 6, 7, 8)

因为服务器可以对owner_id上的索引执行单一范围扫描。您可能无法在所有情况下使用BETWEEN,但如果可以,请执行此操作。

如果此查询对性能至关重要,您可以尝试在

上创建复合索引
(owner_id, id)

并查看它是否加快了查询速度。