将 ORDER BY 子句添加到 MySQL 查询使其在 ~30 秒内返回,高于 ~0.5 秒

Adding ORDER BY clause to MySQL query makes it return in ~30 seconds, up from ~0.5

提问人:Andrew G. Johnson 提问时间:1/15/2009 最后编辑:MachavityAndrew G. Johnson 更新时间:8/17/2017 访问量:2271

问:

所以我有这个查询,它相对较快,为 ~0.5 秒,但是当我添加 ORDER BY 子句时,它会跳到近 30 秒。

原始查询:(在 ~0.5 秒内返回)

SELECT table1.*,table2.* FROM table1 LEFT OUTER JOIN table2 ON table1.column2=table2.column3 WHERE table1.column1='value' LIMIT 4

使用 ORDER BY: 进行查询(在 ~30 秒内返回)

SELECT table1.*,table2.* FROM table1 LEFT OUTER JOIN table2 ON table1.column2=table2.column3 WHERE table1.column1='value' ORDER BY table1.column4 DESC LIMIT 4

注意:我向 ORDER BY 正在使用的列添加了索引,但它没有更改任何内容。

关于是什么原因导致这种情况的任何想法?

MySQL 性能 索引 sql-order-by

评论

0赞 Daniel Schaffer 1/15/2009
column4 是什么类型的列?
0赞 Andrew G. Johnson 1/15/2009
我实际上已经尝试过一些,因为我需要它按不同的字段排序;尝试过 char、varchar 和 int
0赞 Michael Haren 1/15/2009
你能发布实际的表定义(包括索引)吗?你会得到一个更好的答案。
1赞 jishi 1/15/2009
每个查询/表只能使用一个索引,这意味着如果列 1 有一个索引,第 4 列有一个索引,则它只能使用其中一个索引。如果索引同时涵盖 column1 和 column4,则速度可能会更快。
0赞 Michael Haren 1/15/2009
@jishi:是的,但是两个表上协调良好的索引可以产生很大的不同。

答:

10赞 Michael Haren 1/15/2009 #1

这需要更长的时间,因为查询不能只选取它找到的前 4 个项目。它必须对整个列表进行排序,然后从中选择前 4 名。

通过添加包含 table1{column4, ...} 的索引来解决此问题。如果您只需要表 1 中的几列(而且它们很窄),我会将它们全部添加到索引中(覆盖索引)。

如果索引正确,SQL 引擎只能提取所需的前四列,而不是整个集合。

如果您确实有索引,但它没有帮助,请使用 EXPLAIN 运行查询以查看执行计划的外观(好提示,@IronGoofy):

EXPLAIN 
  SELECT table1.*,table2.* 
  FROM table1 
  LEFT OUTER JOIN table2 ON table1.column2=table2.column3 
  WHERE table1.column1='value' ORDER BY table1.column4 DESC LIMIT 4
0赞 JosephStyons 1/15/2009 #2

您如何运行查询?

某些工具通常只检索前 100 条左右的记录,并根据需要下拉更多记录。

添加 ORDER BY 会强制工具检索整个数据集。

如果您使用的是 MySql 浏览器,请尝试在不使用 ORDER BY 的情况下运行,然后使用 CTRL-END 滚动到数据网格的底部。这需要多长时间?

1赞 kdgregory 1/15/2009 #3

table1.column1 是否已编入索引?如果是,则查询优化器将使用该索引从 table1 中选择初始行集,因为它在最坏的情况下是索引范围扫描(非常快)。

如果此查询是频繁运行的查询,则可以通过编制索引 (column1,column4) 来获得所需的性能。我不太了解MySQL,但是使用Oracle,您可以通过索引(column1,column4,column2)来进一步提高性能,这将使优化器从索引中完成所有工作,而不是完全接触表数据。

但是,添加索引是一种权衡:它将增加每次插入(或更新索引列)所花费的时间,使数据库变大,并且由于稀缺的内存资源(即缓冲区缓存)被分配给新索引,可能会导致整体速度变慢。

评论

0赞 Michael Haren 1/15/2009
你是对的 过度索引.正常索引往往有助于选择和更新/删除(必须先找到记录,然后才能更新/删除记录)。我还没有发现一个案例,我在表上有一组合理的索引,并且发现它们损害了性能。
0赞 kdgregory 1/15/2009
我曾经处理过非常密集的写入应用程序。在添加索引之前,我们进行了大量思考,并经常根据客户(基于该客户的特定使用模式)提出建议。我的观点是,“合理”取决于具体情况。
0赞 kdgregory 1/15/2009
(续)更重要的是,在进行数据库物理设计时,您必须牢记每个决策所带来的权衡。
0赞 Michael Haren 1/15/2009
我承认这一点 - 一个重写/轻读系统通常需要一个非常不同的数据库策略。
2赞 Thorsten 1/15/2009 #4

同意迈克尔的解释,+1。

至于索引没有区别,请查看执行计划(不确定如何在MySQL中执行此操作 - 也许有人可以编辑它?同样,我同意 Michael 的观点,这应该会让事情变得更快(只要 column4 是“选择性的”)。

@kogus:将整个结果集检索到客户端与对结果集进行排序不同,排序应该在服务器上进行,而不需要通过网络传输所有结果

0赞 martijnengler 1/15/2009 #5

尝试运行 explain

EXPLAIN SELECT table1.*,table2.* FROM table1 LEFT OUTER JOIN table2 ON table1.column2=table2.column3 WHERE table1.column1='value' ORDER BY table1.column4 DESC LIMIT 4

这可能会告诉你MySQL正在做一个文件排序。你能在(column1, column4)上放一个索引吗?

你能说说更多关于你的模型的信息吗?您使用的是哪些索引?你能展示一些解释输出吗?字段使用哪种类型?

0赞 Adriano Varoli Piazza 1/15/2009 #6

同意迈克尔提到的索引内容。

此外,在MySQL中,您可以通过检查查询前面的EXPLAIN结果来了解查询的性能,例如

EXPLAIN SELECT * FROM foo_tbl WHERE foobar = 'foo'

将帮助您更好地设计查询,并适当地编制索引。阅读 EXPLAIN 语法使用 EXPLAIN 优化查询