JDBC用于选择的巨大数据

时间:2016-02-16 17:29:15

标签: java oracle jdbc prepared-statement where

在我的Java应用程序中,我必须使用WHERE子句从Oracle数据库中选择数据。我将使用准备好的声明。 哪个更好,我应该使用

SELECT column_name FROM table_name WHERE column_name = ?
SELECT column_name FROM table_name WHERE column_name = ?
SELECT column_name FROM table_name WHERE column_name = ?
.
.
.
SELECT column_name FROM table_name WHERE column_name = ?

SELECT column_name FROM table_name WHERE column_name IN (?, ?, ?, ... ?)

我需要在WHERE子句中使用的数据计数可以在01到500之间变化。

3 个答案:

答案 0 :(得分:2)

每个查询执行都带有一些处理/解析/网络开销,因此通过在IN子句中提供值列表,在单个查询中检索多行的速度可以快一个数量级。例如,Oracle必须执行"soft parse"(语法和语义验证,缓存查找),即使查询是可重用的(使用绑定变量),如第一个示例中的情况。

您应该注意,您可以在Oracle的IN子句中包含固定的1000个绑定变量限制。

答案 1 :(得分:0)

如果可能值的数量从1到500不等,那么准备这500个查询可能不值得。我只会每次生成纯SQL(例如SELECT column_name FROM table_name WHERE column_name IN (23,29,31,37))并将其作为普通语句执行。我知道它反对总是准备查询和使用绑定的规则(确保你的代码不受SQL注入攻击)但是规则被破坏了。

答案 2 :(得分:0)

实际上,in()运算符可以更快,但带有(可忽略的)解析成本,加上使用多达500个元素的限制,加上总sql查询文本大小的限制。所以它足够好,但不是火箭证明:)

防火解决方案是在单独的调用中传递任意数量的参数,然后使用视图(或任何其他方式)在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 for SQL是稳定的
  • SQL正在使用一个简单的连接,而不是一个非常快的IN运算符
  • 毕竟,使用任何普通选择或DML命中数据库是一个很好的经验法则,因为它是Oracle,它提供的不仅仅是MySQL或类似的简单数据库引擎。 PL / SQL允许您以有效的方式从应用程序域模型中隐藏存储模型。

这里的诀窍是:

  • 我们需要一个接受长字符串的调用,并存储在db会话可以访问它的地方(例如简单包变量或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引用原始输入字符串。