in() 运算符的局限性是万恶之源。
它适用于琐碎的情况,您可以使用“自动生成准备好的语句”来扩展它,但它总是有其局限性。
- 如果您正在创建具有可变数量参数的语句,这将在每次调用时产生 sql 解析开销
- 在许多平台上,in() 运算符的参数数量是有限的
- 在所有平台上,总 SQL 文本大小是有限的,因此无法为 in 参数发送 2000 个占位符
- 无法发送 1000-10k 的绑定变量,因为 JDBC 驱动程序有其局限性
in() 方法在某些情况下已经足够好了,但不是火箭证明:)
火箭证明解决方案是在单独的调用中传递任意数量的参数(例如,通过传递一组参数),然后有一个视图(或任何其他方式)在 SQL 中表示它们并在你的 where 中使用标准。
蛮力变体在这里http://tkyte.blogspot.hu/2006/06/varying-in-lists.html
但是,如果您可以使用 PL/SQL,那么这种混乱会变得非常整洁。
function getCustomers(in_customerIdList clob) return sys_refcursor is
begin
aux_in_list.parse(in_customerIdList);
open res for
select *
from customer c,
in_list v
where c.customer_id=v.token;
return res;
end;
然后您可以在参数中传递任意数量的逗号分隔的客户 ID,并且:
- 不会有解析延迟,因为 select 的 SQL 是稳定的
- 没有流水线功能的复杂性——它只是一个查询
- SQL 使用简单的连接,而不是 IN 运算符,这非常快
- 毕竟,不使用任何普通的 select 或 DML 访问数据库是一个很好的经验法则,因为它是 Oracle,它提供的光年比 MySQL 或类似的简单数据库引擎还要多。PL/SQL 允许您以有效的方式从应用程序域模型中隐藏存储模型。
这里的诀窍是:
- 我们需要一个接受长字符串的调用,并将其存储在 db session 可以访问它的位置(例如简单的包变量或 dbms_session.set_context)
- 然后我们需要一个可以将其解析为行的视图
- 然后你有一个包含你正在查询的 id 的视图,所以你只需要一个简单的连接到所查询的表。
视图如下所示:
create or replace view in_list
as
select
trim( substr (txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1)
- instr (txt, ',', 1, level) -1 ) ) as token
from (select ','||aux_in_list.getpayload||',' txt from dual)
connect by level <= length(aux_in_list.getpayload)-length(replace(aux_in_list.getpayload,',',''))+1
其中 aux_in_list.getpayload 指的是原始输入字符串。
一种可能的方法是传递 pl/sql 数组(仅由 Oracle 支持),但是您不能在纯 SQL 中使用这些数组,因此始终需要转换步骤。转换不能在 SQL 中完成,所以毕竟,传递一个带有字符串中所有参数的 clob 并在视图中转换它是最有效的解决方案。