Ruby on Rails SQL“SELECT”需要很长时间

时间:2015-07-16 00:35:50

标签: mysql ruby-on-rails ruby sqlite

我从名为“预订”的表中选择包含超过100,000条记录的记录。我是SQL的新手,出于某种原因,这需要花费很多秒才能完成,甚至在我的生产服务器上超时:

def bookings_in_date_range(division, startdate, enddate)
  sql = "SELECT * FROM bookings WHERE division = '#{division}';"
  bookings = ActiveRecord::Base.connection.execute(sql) # all bookings from this division
  bookingsindaterange = bookings.select { |b| (parsedate(b["date"]) >= parsedate(startdate)) and (parsedate(b["date"]) <= parsedate(enddate)) } # refine to bookings in date range
end

def parsedate(date) # get date from mm/dd/yy format
  d = date.split("/")
  return Date.parse("#{d[2]}-#{d[0]}-#{d[1]}")
end

我还包含了用于重新格式化日期的函数,但是根据我的测试,执行SQL语句似乎是进程挂起的位置。

我的目标是在指定日期范围内的“部门”中选择所有“预订”。对于预订数量较少的部门,现有代码的工作速度更快。

修改

下面的Otávio代码似乎可以加快速度。但是,我的要求是查看预订是否在日期范围内(在结束日期或之前的开始日期之前或之后)。我无法弄清楚如何将这个逻辑放入.where语句中,所以我正在运行这样的循环:

    bookings_start_thru_end = []
    (startdate..enddate).each do |date|
      date_bookings = Booking.where("division = ? AND date = ?",division, date.strftime("%m/%d/%y"))
      date_bookings.each do |b|
        bookings_start_thru_end.push b
      end
    end

此外,崩溃的问题是ActiveRecord会话存储填满。我将报告中的一堆数据转储到会话存储中,以便在请求之间保存,以避免执行其他数据库查询,但这会导致性能下降。数据库查询仍然需要5秒左右,但我可以忍受。

2 个答案:

答案 0 :(得分:1)

应尽可能避免在应用程序中执行原始SQL。喜欢使用ActiveRecord接口,这不仅会使您的应用程序更安全,而且还会以优化的方式执行查询。 在您的情况下,重构您的bookings_in_date_range方法以使用ActiveRecord的.where方法:

def bookings_in_date_range(division, enddate, startdate)
  YourModelName.where("division = ? AND enddate = ? AND startdate = ?",division, parsedate(enddate), parsedate(startdate))
end

要查找范围内的内容,请使用

YourModelName.where("division = ? AND enddate <= ? AND startdate >= ?",division, parsedate(enddate), parsedate(startdate))

答案 1 :(得分:1)

使用EXPLAIN查看查询执行计划是什么: https://dev.mysql.com/doc/refman/5.6/en/explain.html https://dev.mysql.com/doc/refman/5.6/en/using-explain.html

现在我的猜测是,您在WHERE中引用的列上没有索引,这会导致表扫描导致查询运行速度非常慢。但这只是我的猜测,因为我不知道你的桌子。

无论您使用的是原始sql还是活动记录(spit),都需要索引。