SQL提高效率:限制FILESORT的数量

时间:2017-02-10 19:10:19

标签: mysql sql mariadb

我要用这样的查询来解释自己:(post_id = PRIMARY,blog_id = index)

SELECT post_id FROM posts WHERE blog_id IN (2,3,...) ORDER BY post_id DESC LIMIT 10

更新:IN()中的ID可能很多。 如果数据库使用blog_id作为查询的键,则必须创建一个filesort,因为索引看起来像这样:

(blog_id,post_id)-> (1,55) (1,59) (1,69) (2,57) (2,71) (2,72) (3,12)

如果您只搜索一个id blog_id = 2而不是IN(),则不需要执行任何文件排序,因为所有匹配都已按顺序排列。

我认为它正在发生的问题,不是100%肯定而是仅仅通过查看查询执行时间,如果我添加一个LIMIT 10,那么有效的方法就是只捕获和归档每个blog_id的最后10个ID索引键匹配,也许它已经这样做了,但看起来像IN(2,3,4)ORDER BY post_id DESC LIMIT 10,它将文件排出数千个ID而不是30个。

我希望我错了,因为如果我不是那个可怜的低效错误。 如果我是对的,我可以做任何引擎或改变吗?甚至改变数据库。目前我在10.1.13-MariaDB上,表格是InnoDB

2 个答案:

答案 0 :(得分:2)

不幸的是,MySQL没有可以让你做你想做的事情的索引。

但是,您可以重写您拥有的查询并使用现有索引:

SELECT p.post_id
FROM ((SELECT post_id
       FROM posts
       WHERE blog_id = 2
       ORDER BY post_id DESC
       LIMIT 10
      ) UNION ALL
      (SELECT post_id
       FROM posts
       WHERE blog_id = 3
       ORDER BY post_id DESC
       LIMIT 10
      )
     ) p
ORDER BY post_id DESC
LIMIT 10;

每个子查询都将使用索引。对20个元素进行排序非常快。

答案 1 :(得分:1)

EXPLAIN SELECT ...;看它是否说" filesort"。

执行以下操作以获取详细信息,即使对于小型数据集也是如此:

FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';

您确实需要INDEX(blog_id, post_id)。如果您使用InnoDB并且表格

PRIMARY KEY(post_id),
INDEX(blog_id)

那么你确实有那个复合索引。这是因为每个二级索引都隐含地包括PK的列。

由于您使用的是MariaDB,请查看LIMIT ROWS EXAMINED是否会执行您询问的其他事项。

当优化工具看到这个时:

WHERE blog_id IN (2,3)
ORDER BY post_id DESC LIMIT 10

并且它同时包含INDEX(blog_id)INDEX(post_id),它会做出决定 - 但在有限的统计数据中 - 关于走哪条路:

计划A:过滤blog_id + filesort或
计划B:以post_id顺序扫描,希望尽快找到10行。

任何一个都有风险。如果大多数或所有行都是(2,3),则计划A将具有较大的排序。计划B,当少于10个匹配行时,将扫描整个表(或索引)。