6

目前正在运行一个简单的 sinatra 应用程序,使用乘客,并使用 pgbouncer 连接到与应用程序位于同一服务器上的数据库。目前我间歇性地收到一个 PG 错误,即准备好的语句“a\d”不存在。

PG::Error 发生在 #:
错误:准备好的语句“a2”不存在

在错误之前执行的 ruby​​ 代码

def self.get_ownership_record(id, key)
  self.where("user_id=?AND key=?", id, key).first
结尾

pgbouncer 配置

; ################################################# #######
; ############# 部分标题[数据库] ################
; ################################################# #######

[数据库]

假数据库=假

[pgbouncer]

; ----- 通用设置 --------------
; -------------------------------------------------
日志文件=/opt/local/var/log/pgbouncer/pgbouncer.log
pidfile=/opt/local/var/run/pgbouncer/pgbouncer.pid
听地址=*
监听端口=5444

; unix_socket_dir=/tmp
用户=_webuser
auth_file=/Users/Shared/data/global/pg_auth
auth_type=信任
pool_mode=事务
; max_client_conn=100
; default_pool_size=20
; Reserve_pool_size=0
; Reserve_pool_timeout=5
; server_round_robin=0

; ----- 日志设置 ------------------
; -------------------------------------------------
; 系统日志=0
; syslog_ident=pgbouncer
; syslog_facility=守护进程
; log_connections=1
; log_disconnections=1
; log_pooler_errors=1

; ----- 控制台访问控制--------
; -------------------------------------------------
admin_users=admin,nagios
; -------------------------------------------------
; server_reset_query=全部丢弃;
 server_check_delay=0
 server_check_query=选择 1;
; server_lifetime=3600
; server_idle_timeout=600
; server_connect_timeout=600
; server_login_retry=15

我唯一的解决方案是关闭准备好的语句吗?

数据库.yml

生产:
  适配器:postgresql
  数据库:假数据库
  用户名:管理员
  主机:本地主机
  端口:5444
  重新连接:真
  准备好的陈述:假

编辑

我已更新 pgbouncer.ini 以使用会话池

pool_mode=session

并且未注释

server_reset_query=DISCARD ALL;

而且我似乎仍然随机出现涉及准备好的语句的错误,但这次

ActiveRecord::StatementInvalid 发生在 #:

PG::Error: 错误:绑定消息提供 2 个参数,但准备好的语句“a1”需要 0

我已经在我的 postgresql 日志中打开了语句级别的日志记录,如果可能的话,我会报告更多详细信息。

4

4 回答 4

3

遵循理查德赫克斯顿的建议,经过反复试验。

我的最终设置看起来像

database.yml

必须设置prepared_statementstrue

生产:
  适配器:postgresql
  数据库:假数据库
  用户名:管理员
  主机:本地主机
  端口:5444
  重新连接:真
  准备好的陈述:真

pgbouncer.ini

不得不取消评论server_reset_query=DISCARD ALL;

并设置pool_mode=session

; ################################################# #######
; ############# 部分标题[数据库] ################
; ################################################# #######

[数据库]

假数据库=假

[pgbouncer]

; ----- 通用设置 --------------
; -------------------------------------------------
日志文件=/opt/local/var/log/pgbouncer/pgbouncer.log
pidfile=/opt/local/var/run/pgbouncer/pgbouncer.pid
听地址=*
监听端口=5444

; unix_socket_dir=/tmp
用户=_webuser
auth_file=/Users/Shared/data/global/pg_auth
auth_type=信任
pool_mode=会话
; max_client_conn=100
; default_pool_size=20
; Reserve_pool_size=0
; Reserve_pool_timeout=5
; server_round_robin=0

; ----- 日志设置 ------------------
; -------------------------------------------------
; 系统日志=0
; syslog_ident=pgbouncer
; syslog_facility=守护进程
; log_connections=1
; log_disconnections=1
; log_pooler_errors=1

; ----- 控制台访问控制--------
; -------------------------------------------------
admin_users=admin,nagios
; -------------------------------------------------
server_reset_query=全部丢弃;
server_check_delay=0
server_check_query=选择 1;
; server_lifetime=3600
; server_idle_timeout=600
; server_connect_timeout=600
; server_login_retry=15

基本上允许使用默认服务器重置查询在会话池模式下准备好语句。

于 2013-11-27T16:31:53.887 回答
1

也许阅读常见问题解答会有所帮助?除非您有充分的理由不这样做,否则会话池应该是明智的。

于 2013-11-22T17:21:24.503 回答
0

您可以使用事务池,前提是您PREPAREEXECUTE准备好的查询在同一个事务中(以避免 pgBouncerserver_reset_query在两者之间运行)。

于 2017-08-07T08:06:05.127 回答
0

在我的情况下,访问 postgres 目录并运行“DEALLOCATE ALL”可以解决问题。

如果你使用heroku,像这样

> heroku pg:psql -a app_name
app_name::DATABASE=> DEALLOCATE ALL
于 2017-11-15T11:28:36.257 回答