【问题标题】:JDBC Huge data for select用于选择的 JDBC 海量数据
【发布时间】:2016-02-16 17:29:14
【问题描述】:

在我的 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 不等。

【问题讨论】:

    标签: java oracle jdbc prepared-statement where


    【解决方案1】:

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

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

    【讨论】:

    • 是的,我知道 IN 子句中有 1000 个限制。您知道比迭代追加“,”和“?”更好的方法在 IN 子句中,因为我的 IN 子句数据在 ArrayList 中?
    • This thread 有一些替代方法可以使用绑定占位符动态生成查询。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      实际上,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 的 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 指的是原始输入字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-07
        • 2011-06-28
        • 1970-01-01
        相关资源
        最近更新 更多