【问题标题】:How to disable prepared statement in heroku with postgres database如何使用 postgres 数据库在 heroku 中禁用准备好的语句
【发布时间】:2014-04-02 13:55:27
【问题描述】:

我在本地(使用 postgres 配置)修复了我的 rails 项目的一个问题,同时在 database.yml 中添加了以下语句:

test:
  prepared_statements: false

我修复的错误与此问题有关:

 PG::ProtocolViolation: ERROR: bind message supplies 2 parameters, but prepared            statement "a24" requires 1 

现在,我想在 Heroku 上使用 postgres 数据库托管的生产应用程序上修复它。我不知道如何禁用准备好的语句,因为 database.yml 是自动生成的。我试图追加:

/database?prepared_statements=false

到我的数据库的 URI,但它以错误的 DATABSE_URL 结尾,因此我无法连接到我的数据库。

禁用prepared_statement的过程和正确的语法是什么?

【问题讨论】:

  • 你更多地“解决”了这个问题,而不是实际修复它。如果 ActiveRecord、Pg gem 等中存在真正的错误,最好有一个独立的测试用例来演示它。 (不能真正帮助您在 Heroku 上应用解决方法,没有太多使用它的应用托管)。

标签: ruby-on-rails postgresql heroku


【解决方案1】:

截至 2014 年 2 月 19 日,heroku no longer overrides database.yml 因此您可以按照latest docs 的建议关闭database.yml 文件的productionstaging(或default)块中的准备好的语句:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  prepared_statements: false

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  url:  <%= ENV['DATABASE_URL'] %>
  pool: <%= ENV['DB_POOL'] || ENV['MAX_THREADS'] || 5 %>

staging:
  <<: *default
  url:  <%= ENV['DATABASE_URL'] %>
  pool: <%= ENV['DB_POOL'] || ENV['MAX_THREADS'] || 5 %>

【讨论】:

  • 这对我来说正确地将prepared_statements 设置为 false。您可以在rails console 中运行ActiveRecord::Base.configurations[Rails.env] 来验证它。
  • 链接到 heroku 文章关于如何禁用准备好的语句,如 markquezada 的回答中成功描述的那样:devcenter.heroku.com/articles/…
【解决方案2】:

我们担心暂存/生产(在 Heroku 上使用 DATABASE_URL)和开发/测试(使用 database.yml/database.example.yml)之间的脆弱性和保持一致性。

Rails' tests 的启发,我们将其放入 config/initializers/disable_prepared_statements.rb:

ActiveRecord::Base.establish_connection(
  ActiveRecord::Base.remove_connection.merge(
    :prepared_statements => false
  )
)

remove_connection 返回被删除连接的连接参数的哈希值。这应该让任何 database.yml 或 DATABASE_URL 继续工作。

【讨论】:

  • 这对我不起作用:ActiveRecord::Base.configurations 不包含prepared_statements => false
【解决方案3】:

您应该能够将?prepared_statements=false 添加到现有的数据库网址并重新启动您的测功机。这对我们有用。

heroku config:add DATABASE_URL=[old database url here]?prepared_statements=false

要在重新启动服务器后检查它是否已设置,您可以打开控制台并查询 ActiveRecord::Base.connection_config

【讨论】:

    【解决方案4】:

    您可以在初始化程序中将配置哈希传递给 ActiveRecord::Base.establish_connection。例如:

    configure :production, :development, :test do
      db = URI.parse(ENV['DATABASE_URL']
    
      ActiveRecord::Base.establish_connection(
          :adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
          :host                => db.host,
          :username            => db.user,
          :password            => db.password,
          :database            => db.path[1..-1],
          :encoding            => 'utf8',
          :prepared_statements => false,
      )
    end
    

    http://apidock.com/rails/ActiveRecord/Base/establish_connection/class

    【讨论】:

      【解决方案5】:

      最近似乎 Heroku 已禁用使用 heroku config:set DATABASE_URL=&lt;blah&gt;?prepared_statements=false 设置 DATABASE_URL,给我们返回错误“▸ 无法覆盖附件值 DATABASE_URL。”

      为了解决这个问题,我们在 config/ 中添加了 disabled_prepared_statements.rb 初始化程序,其中包含:

      ActiveRecord::Base.configurations[Rails.env].merge!(prepared_statements: false)

      【讨论】:

        【解决方案6】:

        关闭准备好的语句会降低性能,因为 postgresql 必须在执行之前重新计划每个查询,所以我不建议在生产服务器上关闭它——尤其是当你不小心时,rails 会执行许多小查询而臭名昭著关于急于加载所有内容。我建议在每次部署后弄清楚如何在不影响服务可用性的情况下实时重启。我不是 Rails 专家,但我知道这是可行的(我们公司就是这样做的)。这里有更多关于为什么会发生这种情况的见解https://github.com/rails/rails/issues/12330

        【讨论】:

        • 那个问题是这样的
        • @kristok 您能否就如何进行渐进式部署提供任何建议,而不会遇到准备好的语句问题?除了禁用它们之外,我没有看到该问题提供任何解决方案。说有可能但不提供任何见解并不是很有帮助。
        • @lobati 没有简单的解决方案,这就是为什么它没有被提供。谷歌的通用方法是“rails 零停机部署”,基本上每个人都在构建自己的复杂程序来克服 rails 的缺点。
        • @kristok “rails 零停机部署”的谷歌结果倾向于解决如何保持数据库和代码在两个版本的代码之间兼容。我没有看到任何可以解决如何使用准备好的语句处理活动记录问题的方法。我确实看到一些建议禁用它,以便可以使用 pg_bouncer 扩展数据库。
        • @lobati 并且只要 Rails 迁移像它们一样被破坏,这就是要走的路,除非您打算深入挖掘并修复它。在我编写 rails 的 9 个月中,我见过的最糟糕的情况是,在开发人员的盒子上,已经稳定了 4 年的迁移突然中断了,因为 rails 改变了版本之间的 DDL 生成逻辑。在那之后,真的没有办法基于现有的迁移来拥有一个可重现的实时结构,所以我们只是在迁移中加入了一些东西,以使开发环境类似于实时。所以我最好的答案是遵循那些代码兼容性规则
        猜你喜欢
        • 1970-01-01
        • 2020-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多