修改PostgreSQL字段长度导致cached plan must not change result type错误

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: 修改PostgreSQL字段长度可能导致cached plan must not change result type错误

问题

有业务反馈在修改一个表字段长度后,Java应用不停的报下面的错误,但是越往后错误越少,过了15分钟错误就没有再发生。

### Error querying database.  Cause: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type

原因

调查判断原因是修改字段长度导致执行计划缓存失效,继续使用之前的预编译语句执行会失败。

很多人遇到过类似错误,比如:

但是,有两个疑问没有解释清楚。

  1. 以前业务也改过字段长度,但为什么没有触发这个错误?
  2. 这个错误能否自愈?

下面是进一步的分析

PostgreSQL中抛出此异常的代码如下:

static List *
RevalidateCachedQuery(CachedPlanSource *plansource,
                      QueryEnvironment *queryEnv)
{
        if (plansource->fixed_result)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("cached plan must not change result type")));
...
}

pgjdbc代码里有对该异常的判断,发生异常后,后续的执行会重新预编译,不会继续使用已经失效的预编译语句。这说明pgjdbc对这个错误有容错或自愈能力。

  protected boolean willHealViaReparse(SQLException e) {
...
    // "cached plan must not change result type"
    String routine = pe.getServerErrorMessage().getRoutine();
    return "RevalidateCachedQuery".equals(routine) // 9.2+
        || "RevalidateCachedPlan".equals(routine); // <= 9.1
  }

发生条件

经验证,使用Java应用时本故障的发生条件如下:

  1. 使用非自动提交模式
  2. 使用prepareStatement执行相同SQL 5次以上
  3. 修改表字段长度
  4. 表字段长度修改后第一次使用prepareStatement执行相同SQL

测试验证

以下代码模拟Java连接多次出池->执行->入池,中途修改字段长度。可以复现本问题

         Connection conn = DriverManager.getConnection(...);   
         conn.setAutoCommit(false); //自动提交模式下,不会出错,pgjdbc内部会处理掉
         String sql = "select c1 from tb1 where id=1";   
         PreparedStatement prest =conn.prepareStatement(sql);   
         
         for(int i=0;i<5;i++)
         {
             System.out.println("i: " + i);
             prest =conn.prepareStatement(sql);
             ResultSet rs = prest.executeQuery();
             prest.close();
             conn.commit();
         }
         
         //在这里设置断点,手动修改字段长度: alter table tb1 alter c1 type varchar(118);
         
         for(int i=5;i<10;i++)
         {
             System.out.println("i: " + i);
             try {
             prest =conn.prepareStatement(sql);
             ResultSet rs = prest.executeQuery();
             prest.close();
             conn.commit();
             } catch (SQLException e) {
                 System.out.println(e.getMessage());
                 conn.rollback();
             }
         }
        conn.close(); 

测试程序执行结果如下:

i: 0
i: 1
i: 2
i: 3
i: 4
i: 5
ERROR: cached plan must not change result type
i: 6
i: 7
i: 8
i: 9

回避

  1. 在不影响业务逻辑的前提下,尽量使用自动提交模式
  2. 修改表字段长度后重启应用,或者在业务发生该SQL错误后重试(等每个Jboss缓存的连接都抛出一次错误后会自动恢复)
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
SQL 关系型数据库 分布式数据库
PostgreSQL 在线修改数据类型 - online ddl 方法之一
标签 PostgreSQL , online ddl , trigger , ddl 事务 背景 有张表的主键id是serial,但现在不够了,需要升级成bigserial,有什么优雅的方法吗?我看下来好像会锁表很久(因为数据量挺大) 如果直接alter table,由于数据类型从4字节改成了8字节,而tuple结构是在METADATA里面的,不是每行都有,所以DEFORM需要依赖METADATA,目前来说,这种操作需要rewrite table。
3625 0
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 11 新特性解读 : Initdb/Pg_resetwal支持修改WAL文件大小
PostgreSQL 11 版本的一个重要调整是支持 initdb 和 pg_resetwal 修改 WAL 文件大小,而 11 版本之前只能在编译安装 PostgreSQL 时设置 WAL 文件大小。
8711 0
|
SQL 关系型数据库 数据库连接
PostgreSQL 修改数据库属性
PostgreSQL 修改数据库属性
96 0
|
关系型数据库 MySQL PostgreSQL
ruoyi数据源修改为PostgreSQL分页错误
ruoyi数据源修改为PostgreSQL分页错误
130 0
|
消息中间件 数据采集 监控
ELK搭建(七):搭建PostgreSQL慢查询、错误日志监控平台
PostgreSQL是一款功能非常强大的的关系性数据库,适用于需要执行复杂查询的系统。市面上越来越多的公司开始采用PostgreSQL作为主数据库。 今天我们就来讲解如何搭建一个PostgreSQL的慢日志、错误日志监控平台,实时了解到数据库的日志情况,来帮助我们快速排错及优化。
641 0
ELK搭建(七):搭建PostgreSQL慢查询、错误日志监控平台
|
SQL 存储 缓存
Citus 分布式 PostgreSQL 集群 - SQL Reference(摄取、修改数据 DML)
Citus 分布式 PostgreSQL 集群 - SQL Reference(摄取、修改数据 DML)
124 0
|
SQL NoSQL 关系型数据库
PostgreSQL 打印详细错误调用栈 - pg_backtrace
PostgreSQL 打印详细错误调用栈 - pg_backtrace
1746 0
|
SQL 弹性计算 NoSQL
PostgreSQL 打印详细错误调用栈 - pg_backtrace
标签 PostgreSQL , pg_backtrace , 错误调用栈 , core 背景 PostgreSQL 使用backtrace,让PG的user process支持self-debugging。 NAME backtrace, backtrace_symbols, backtrace_symbols_fd - support for application
656 0
|
SQL 关系型数据库 MySQL
RDS Mysql数据修改后2小时之后才查到
问题背景: 用户的rds数据库,最近出现了这样一个问题:没有使用读写分离,提交一个update语句修改状态值,修改之后,当时查不到修改后的值,查到的还是修改前的值,过了2小时之后才可以查到,审计日志看sql语句是更新成功的。
1105 0
|
关系型数据库 PostgreSQL
PostgreSQL之连接数修改
当前总共正在使用的连接数 select count(1) from pg_stat_activity; 显示系统允许的最大连接数 show max_connections; 显示系统保留的用户数 show superuser_reserved_connections ; 按照用户分组查看 ...
4487 0