Rails真的缓存数据库查询吗?

时间:2017-02-21 03:39:10

标签: ruby-on-rails rails-activerecord

Rails是否实际缓存了查询结果? The documentation表示相同的查询将永远不会在同一请求上执行两次

  

1.7 SQL缓存

     

第二次对数据库运行相同的查询时,它实际上不会命中数据库。第一次从查询返回结果时,它将存储在查询缓存中(在内存中),第二次从内存中提取。

我做了一个实验来证明Rails实际缓存了查询:

  def test
    data = ""
    User.find(1).update(first_name: 'Suwir Suwirr')
    data << User.find(1).first_name
    data << "\n"

    User.find(1).update(first_name: 'Pengguna')
    data << User.find(1).first_name
    data << "\n"

    render plain: data
  end

如果结果被缓存,我将为每个User.find(1)获得相同的结果。但是,结果是Rails实际上并不缓存查询;我期待update没有反映在结果上,因为它被“缓存”了:

Suwir Suwirr
Pengguna

但是控制台说它被缓存 :(请突出显示CACHE字)

Started GET "/diag/test" for 10.0.2.2 at 2017-02-21 10:30:16 +0700
Processing by DiagController#test as HTML
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 4], ["LIMIT", 1]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (0.1ms)  BEGIN
  SQL (0.4ms)  UPDATE "users" SET "first_name" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [["first_name", "Suwir Suwirr"], ["updated_at", 2017-02-21 03:30:16 UTC], ["id", 1]]
   (16.5ms)  COMMIT
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
   (0.1ms)  BEGIN
  SQL (0.3ms)  UPDATE "users" SET "first_name" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [["first_name", "Pengguna"], ["updated_at", 2017-02-21 03:30:16 UTC], ["id", 1]]
   (0.9ms)  COMMIT
  User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering text template
  Rendered text template (0.0ms)
Completed 200 OK in 380ms (Views: 3.5ms | ActiveRecord: 21.9ms)

所以我的问题,Rails实际上是否缓存了查询结果?或者,在某些请求中只有几个查询结果?

更新:使用批处理#update_all

我做了另一个实验来“愚弄”查询逻辑。现在Rails不会“缓存”查询。为什么会出现这种情况?

# Controller
  def test
    data = ""
    User.where(id: 1).update_all(first_name: 'Suwir Suwirr')
    data << User.find(1).first_name
    data << "\n"

    User.where(id: 1).update_all(first_name: 'Pengguna')
    data << User.find(1).first_name
    data << "\n"

    logger.info 'hi'

    render plain: data
  end

# Console
Started GET "/diag/test" for 10.0.2.2 at 2017-02-21 10:45:43 +0700
Processing by DiagController#test as HTML
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 4], ["LIMIT", 1]]
  SQL (13.8ms)  UPDATE "users" SET "first_name" = 'Suwir Suwirr' WHERE "users"."id" = $1  [["id", 1]]
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  SQL (2.9ms)  UPDATE "users" SET "first_name" = 'Pengguna' WHERE "users"."id" = $1  [["id", 1]]
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
hi
  Rendering text template
  Rendered text template (0.0ms)
Completed 200 OK in 28ms (Views: 0.8ms | ActiveRecord: 17.8ms)

# Browser result
Suwir Suwirr
Pengguna

1 个答案:

答案 0 :(得分:2)

我很蠢。

是的,Rails实际上会缓存查询,但updatedestroy将使其查询缓存无效。 update_all基本上是使用update迭代每条记录。

我通过真正“愚弄”ActiveRecord查询机制来尝试实验。是的,它有效。

# Controller
  def test
    data = ""
    ActiveRecord::Base.connection.execute('UPDATE "users" SET "first_name" = \'Suwir Suwirr\' WHERE "users"."id" = 1')
    data << User.find(1).first_name
    data << "\n"

    ActiveRecord::Base.connection.execute('UPDATE "users" SET "first_name" = \'Pengguna\' WHERE "users"."id" = 1')
    data << User.find(1).first_name
    data << "\n"

    render plain: data
  end

# Browser
Suwir Suwirr
Suwir Suwirr