PostgreSQL 8.3.7服务器将此异常抛给我的应用程序.有谁知道这个错误意味着什么,我能做些什么呢?
ERROR: cached plan must not change result type
STATEMENT: select code,is_deprecated from country where code=$1
Run Code Online (Sandbox Code Playgroud) 根据PostgreSQL文档,预准备语句绑定到数据库会话/连接:
PREPARE创建一个准备好的声明.预准备语句是服务器端对象,可用于优化性能.执行PREPARE语句时,将解析,分析和重写指定的语句.随后发出EXECUTE命令时,将计划并执行准备好的语句.
准备语句仅持续当前数据库会话的持续时间.会话结束时,忘记了准备好的语句,因此必须重新创建它才能再次使用.
但是,Markus Winand(SQL Performance Explained的作者)说:
PostgreSQL没有共享查询计划缓存,但它具有用于预准备语句的可选查询计划缓存.这意味着开发人员可以选择使用带有或不带缓存查询计划的预准备语句.但请注意,在准备好的语句关闭时,缓存将被删除.
哪一个是真的?
只要数据库连接处于打开状态,预准备语句是否存在,因此在使用连接池时,只要池没有显式关闭物理连接,或者JDBC一旦消除了服务器端预准备语句,它就可以存在PreparedStatement已关闭.
目前运行一个简单的sinatra应用程序,使用乘客,并使用pgbouncer连接池到与应用程序在同一服务器上的数据库.目前我间歇性地得到PG错误,准备好的声明"a\d"不存在.
A PG::Error occurred in #: ERROR: prepared statement "a2" does not exist
在错误之前执行的ruby代码
def self.get_ownership_record(id, key)
self.where("user_id=? AND key=?", id, key ).first
end
pgbouncer配置
; ######################################################### ; ############# SECTION HEADER [DATABASES] ################ ; ######################################################### [databases] fakedatabase=fake [pgbouncer] ; ----- Generic Settings -------------------------- ; ------------------------------------------------- logfile=/opt/local/var/log/pgbouncer/pgbouncer.log pidfile=/opt/local/var/run/pgbouncer/pgbouncer.pid listen_addr=* listen_port=5444 ; unix_socket_dir=/tmp user=_webuser auth_file=/Users/Shared/data/global/pg_auth auth_type=trust pool_mode=transaction ; max_client_conn=100 ; default_pool_size=20 ; reserve_pool_size=0 ; reserve_pool_timeout=5 ; server_round_robin=0 ; ----- Log Settings ------------------------------ ; ------------------------------------------------- ; syslog=0 ; syslog_ident=pgbouncer ; syslog_facility=daemon ; log_connections=1 …
默认情况下,参数语句treshold设置为5,而不是1.也就是说,
((PGStatement) my_statement).getPrepareThreshold()
Run Code Online (Sandbox Code Playgroud)
默认情况下始终返回5.
这是什么原因?为什么我不想在执行查询的前4次使用服务器端预处理语句?我无法理解为什么我会将其设置为另一个值而不是1,以及为什么默认设置为1.
你可以解释吗?非常感谢.
假设我想在表中添加一列。如果我在数据库中添加列而不重新启动应用程序,我的应用程序将开始失败,并显示“缓存计划不得更改结果类型”,因为在添加此列后执行通配符选择的查询的返回类型会发生变化。
jdbc postgres 驱动程序在一定阈值后自动创建准备好的语句,默认阈值为 5。
我可以通过将prepareThreshold设置为0来禁用它,这很糟糕,因为我失去了准备好的语句优化驱动程序为我带来的好处。
或者我必须更改所有 SQL 语句以指定它将操作的确切列列表。因此,编写像“SELECT * FROM TABLE”这样的语句是不可行的。
还有其他方法可以解决这个问题吗?