Rails / Oracle:ActiveRecord发现从控制台和应用程序返回不同的结果

时间:2013-06-10 16:10:06

标签: ruby-on-rails oracle activerecord

我最近开始将我的应用程序从使用sqlite转移到Oracle,并开始遇到以下问题:

使用rails 3.2.13,Oracle 11.2.0.3.0和activerecord-oracle_enhanced-adapter(1.4.2),我的控制器中有以下内容:

def show
    if params.has_key?('user_id')
      @user = User.find(params[:user_id])
    else
      @user = current_user
    end
    @user_id = @user.id

    @activity_date = Date.parse(params[:id])
    #@activity_date = Activity.all.first.activity_date

    @activities = Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date)
    logger.warn "----- count is #{@activities.count} ------"
return
  • 应用程序 正好找到0条记录 (根据记录器输出以及@user和@activity_date的相应值)。

    < / LI>
  • development.log将生成的查询报告为:

    SELECT COUNT(*)FROM“ACTIVITIES”WHERE(user_id = 10594 AND to_date(activity_date)= TO_DATE('2013-06-05','YYYY-MM-DD HH24:MI:SS'))

如果我从SQL * Plus运行此查询,我会得到4条记录 - ,我期待   - 因此看起来AR返回的结果与查询AR返回的结果报告给我的日志之间存在差异。

  • 此外,如果我捣乱并使用类似

    之类的方式在where调用之前手动设置日期

    @activity_date = Activity.all.first.activity_date

第一个活动日期恰好是“正确的”活动日期,Rails返回所有4行,因此控制台和应用程序指向同一个数据库。

据我所知:

  • Rails正在生成一个有效的查询,因此进入.where方法的值是正常的
  • 所述查询返回“正确”数量的结果,*从SQL * Plus *
  • 运行时
  • 控制台和应用程序指向相同的数据库
  • 但是Rails似乎“看到”了错误的结果数量。

发生了什么事?我已经没有头发了。

编辑根据David Aldridge的建议,删除了在活动日期占位符的TO_DATE调用;仍然没有得到正确的结果集。 编辑根据大卫的建议:

 @user_id=10594
 @activity_date=Date.parse('2013-06-13')

####### **Returned wrong set of results**
####### Note class of @activity_date is Date
    bundler-0.9.24 :083 > @activity_date.class
    => Date 

    bundler-0.9.24 :084 > Activity.where("user_id = ? AND activity_date = ?", @userid, @activity_date).explain
      Activity Load (1.8ms)  SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-13','YYYY-MM-DD HH24:MI:SS'))
      EXPLAIN (7.8ms)  EXPLAIN PLAN FOR SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-13','YYYY-MM-DD HH24:MI:SS'))

####### **Returned right set of results**
    bundler-0.9.24 :089 > @activity_date=Activity.all.first.activity_date
      Activity Load (1.5ms)  SELECT "ACTIVITIES".* FROM "ACTIVITIES" 
    => Wed, 05 Jun 2013 04:00:00 UTC +00:00 

#### Note class of @activity_date is different from above**

    bundler-0.9.24 :090 > @activity_date.class
    => ActiveSupport::TimeWithZone 
    bundler-0.9.24 :091 > Activity.where("user_id = ? AND activity_date = ?", @userid, @activity_date).explain
**And note generated query includes a time specification whereas previous query did not**
      Activity Load (2.7ms)  SELECT "ACTIVITIES".* FROM "ACTIVITIES" WHERE (user_id = NULL AND activity_date = TO_DATE('2013-06-05 04:00:00','YYYY-MM-DD HH24:MI:SS'))

解决 当我创建activity_date字段时,我使用了Date.civil。我忽略了认为Oracle称之为“Date”类型的实际上也包含Time组件。

由于Date.civil没有时区,我存储的activity_date本质上是一个DateTime,偏移本地时区(因为Date.civil不占用时区)。由于我的应用程序忽略了实际的时间,我通过使用DateTime.civil而不是Date.civil来计算activity_date来解决这个问题。感谢David Aldridge的帮助,并向我道歉,我没有足够的代表来支持他。

1 个答案:

答案 0 :(得分:0)

activity_date列实际上是日期,还是需要转换为日期的字符串?

如果是前者那么to_date是错误放置的,并且不应该出现。

@activities = Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date)

它可能在一个环境而不是另一个环境中工作的原因是环境对nls_date_parameter具有不同的值,无论是对于数据库还是对于会话。

这里有用的诊断可能是解释计划,如果rails使用DBMS_XPlan来获取计划,则应显示隐式数据转换。您应该能够通过控制台获取计划:

Activity.where("user_id = ? AND activity_date = ?", @user.id, @activity_date).explain

在SQL * Plus中运行查询,然后运行:

select * from table(dbms_xplan.display);

...应该为您提供SQL * Plus正在使用的计划。

如果你在问题中发帖,它可能有助于未来遇到问题。