Oracle 绑定变量过多导致 DML 阻塞

生产有个功能是上传一个 excel 来进行批量数据操作,excel 里面有三列数据,构建出来的查询大概如下:

select * from t_test t where (t.col1, t.col2, t.col3) in (
(:1, :2, :3),
(:4, :5, :6)
)

IN 子句的长度取决于上传的 excel 里的行数,每一行对应一个 元组。

由于没有限制 excel 里最大行数,导致构建出来的 SQL 有1万多个绑定变量,然后这个 SQL 一直处于解析中,阻塞了这个表上的其他操作(当时主要是插入操作)。(DBA 联系厂商分析给出的结论)

之前一直以为 IN 的列表不能超过 1000,那么生产为什么没有报错,当时拿了那个引发问题的 excel 文件在测试环境复现,是可以正常执行完成的。
DBA 的解释是 11g 里不会报错,19c 开始会报错。DBA 另外提到 IN 列表过长的执行效率是不高的,IN 列表每多一行,执行计划 UNION ALL 下也多一行:

今天重新提起这个,有同事写了个 SQL 在本地验证是报错的:

select * from t_test t where t.col1 in (1, 2, 3, ..., 1001);

为啥当时测试环境复现通过,这个为啥报错?必须搞清楚了。

原因如下:
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/Expression-Lists.html#GUID-5CC8FC75-813B-44AA-8737-D940FA887D1E

A comma-delimited list of expressions can contain no more than 1000 expressions. A comma-delimited list of sets of expressions can contain any number of sets, but each set can contain no more than 1000 expressions.
用逗号分隔的表达式列表中不能包含超过1000个表达式。用逗号分隔的表达式集合列表可以包含任意数量的集合,但每个集合不能包含超过1000个表达式。

顺便狗到了 IN 怎么超过 1000 的方法:

select * from worktracker
where rmid in ( 1, ..., 999 )
or rmid in ( 1001, ..., 1999 )
or ...

select * from worktracker
where ( 1, rmid ) in (
( 1, '1001' ),
( 1, '1212' ),
...
)


欢迎关注我的微信公众号: coderbee笔记

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据