【问题标题】:Query is fast in MySQL but slow when run from Rails ActiveRecord查询在 MySQL 中很快,但在 Rails ActiveRecord 中运行时很慢
【发布时间】:2011-06-27 14:44:08
【问题描述】:

我有一个查询在 MySQL 控制台中运行非常快,但在我使用 Rails Active Record 运行时却非常慢。这是针对包含 700 万条记录的表运行的查询:

select broker_id,count(abserror),avg(abserror) from fc_estimates where (fpe > '2000-05-28') and (fpe group by broker_id order by broker_id;

运行需要 3 分钟。

然后我在 Rails Active Record 中运行这个查询:

统计 = 估计。 选择([ "broker_id", "count(abserror) as abserror_count", “avg(abserror) as abserror_avg” ])。 哪里( :fpe => ((fpe-1098).to_date..(fpe+30).to_date)) (“broker_id”)。 订单("broker_id")

生成这个 sql(从 to_sql 输出)

SELECT broker_id, count(abserror) as abserror_count, avg(abserror) as abserror_avg FROM fc_estimates WHERE (fc_estimates. fpe BETWEEN '2000-05-28' AND '2003-06-30') GROUP BY broker_id ORDER BY broker_id

运行需要 1 小时 40 分钟。它返回 250 条记录。

我正在使用 Windows 7、MySQl 5.1、Ruby 1.8.7、ActiveRecord 3.04、mysql2 gem 0.2.6

这些是 InnoDB 表,我已将 innodb_buffer_pool_size 增加到 480M(这确实有助于其他查询)。我观察到的一件事是 MySQL 内存使用量增加到大约 500M,然后有很多磁盘活动(页面交换)。这确实解释了一些事情。

但是,当在 MySQL 控制台中运行相同的查询只需要 3 分钟时,为什么我的性能如此糟糕?感谢您提出任何想法或遇到类似情况的任何人。

2011 年 2 月 24 日更新

我更新到 MySQL 5.5。现在我在控制台中的查询运行大约 1 分 40 秒。使用 ActiveRecords 大约需要 40 分钟。

【问题讨论】:

  • 您可能会看到 mysql 查询缓存的结果。尝试在 mysql 中再次计时查询,但将 SQL_NO_CACHE 放在 SELECT 之后以禁用查询缓存。
  • 是的,我想我明白了。我第二次在控制台中运行查询时,它运行得非常快。所以我的查询在 3 分钟内运行 - 第二次运行速度非常快。我不认为是这样,但我会检查。
  • 针对如此少的行数 3 分钟有点令人担忧 - 如果您利用 innodb 聚集索引,您可能会获得不到 1 秒的运行时间。
  • 刚刚再次运行查询。在 MySQL 控制台中,查询需要 4 分钟,再次运行需要 1 分钟 14 秒,再次运行需要 3 秒,再次运行需要 3 秒。所以我猜这是查询缓存生效。然后我使用 SELECT SQL_NO_CACHE ... 运行,查询耗时 2 分钟,再次使用 SELEC SQL_NO_CACHE,查询耗时 3 分 30 秒。实际上我的问题是磁盘被颠簸(有很多写入到 c:\pagefile.sys)。但为什么会这样呢?
  • 3 分钟对我来说没问题 - 这不是一个 Web 应用程序。当我使用 ActiveRecord 时,1 小时 40 分钟很痛苦。

标签: mysql ruby-on-rails performance activerecord


【解决方案1】:

在您的 ruby​​ 代码中运行的不仅仅是 SQL 查询。我不是红宝石绝地,但我可以指出一些东西。

Windows 不是使用 MRI 的最佳位置。也许您应该尝试 1.9.2 或 JRuby - 甚至切换到某些 *nix 操作系统。

(fpe-1098).to_date..(fpe+30).to_date) 为日期间隔构建一个 Range 实例。也许您应该尝试不同的语法,即:['fpe > ? AND fpe < ?'(fpe-1098),(fpe+30)] - 这样会创建更少的对象。

由于您没有检索Estimate 实例,因此您可以将生成的sql 传递给ActiveRecord::Base.connection.execute,而不是使用模型类运行查询。也许会有更少的内存使用和创建的对象。

【讨论】:

  • 谢谢,所有优秀的 cmets。我试过同时使用 Ruby 1.8.7 和 Ruby 1.9.2 并没有太大区别。 JRuby,我想可以试试。
  • 但是对于查询本身是的,它可以做得更好。我只是想计算一个日期范围内的平均值 - 但这些日期实际上只是月末日期,所以在三年的时间里,我将只有 36 个不同的日期。所以现在我分两个阶段做。首先,只需计算一个日期的计数和平均值。其次,使用这些统计数据(计数和平均值)计算三年(36 个月)期间的总体平均值。
猜你喜欢
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多