1

orders表有 2m 条记录。有 ~900K 独特ship-to-id的 s。

ship_to_id(字段为int(8))上有一个索引。

下面的查询需要将近 1000 万才能完成。我已经运行PROCESSLISTCommand=QueryState= Sending Data

当我运行时explain,使用现有索引,并且possible_keysNULL.

我应该做些什么来加快这个查询?谢谢。

SELECT 
  ship_to_id as customer_id 
FROM orders 
GROUP BY ship_to_id 
HAVING SUM( price_after_discount ) > 0
4

3 回答 3

4

看起来您没有有用的索引。尝试在 price_after_discount 上添加索引,并添加如下条件:

WHERE price_after_discount > 0

尽量减少需要求和的行数,因为您显然可以丢弃任何为 0 的行。

还可以尝试运行“top”命令并在查询运行时查看 io“wait”列。如果它很高,则意味着您的查询会导致大量磁盘 I/O。如果您有 RAM 来加快速度(如果您使用的是 innodb),则可以增加各种内存缓冲区,或者 myisam 是通过文件系统缓存完成的。重新启动服务器将刷新这些缓存。

如果您没有足够的 RAM(对于 2M 记录,您不应该需要太多 RAM),那么请考虑针对可能 ship-to-ids 列的分区方案(如果您的 mysql 版本支持它)。

于 2013-05-08T19:27:07.240 回答
2

如果该表中的所有订单都不是最新的(即不会再次更改),那么您可以将它们归档到另一个表中以减少必须扫描的数据量。

另一种选择是last_modified在带有索引的表上抛出时间戳。然后,您可以跟踪查询何时运行并将结果存储在另一个表 ( query_results) 中。当需要再次运行查询时,您只需选择自上次运行查询以来修改过的订单,然后使用它来更新query_results. 逻辑稍微复杂一些,但假设在查询执行之间更新的订单比例较低,它应该会快得多。

于 2013-05-08T19:47:40.410 回答
2

MySQL使用 a 的索引group by,至少根据文档,如此处所述

为了最有用,查询中使用的所有列都应该在索引中。这可以防止引擎必须引用原始数据以及索引。因此,尝试在orders(ship_to_id, price_after_discount).

于 2013-05-08T19:47:44.953 回答