查询需要很长时间

时间:2013-05-23 09:22:23

标签: sql oracle

我有这个查询(在oracle中)需要很长时间(15-30秒)( query1 ):

SELECT numcen
  FROM centros
 WHERE TO_NUMBER (centros.numcen) = TO_NUMBER (?)
    OR TO_NUMBER (centros.numcen) IN (
          SELECT TO_NUMBER (dc.centro)
            FROM datos_centro dc, centros c
           WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
             AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));

我不知道为什么,因为这是一个非常简单的查询。我认为这是因为IN中的子查询,但是如果我运行这样的子查询( query2 ):

SELECT TO_NUMBER (dc.centro)
  FROM datos_centro dc, centros c
 WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
   AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?)

只需要100-200ms。 更重要的是,如果我运行 query2 并将其结果放在{em> query1 替换子查询中的IN内,则结果立即生效。

我无法运行解释计划因为我没有权利。 如果我在mysql下运行(由TO_NUMBER替换CAST),情况会更糟。这需要2分钟以上,这是不可接受的。

那么,有没有办法改进第一个查询( query1 )?我应该分成两部分吗?如果我将OR替换为UNION(这要快得多),它会是同一个查询吗?

非常欢迎任何建议。谢谢,抱歉我的英语。

3 个答案:

答案 0 :(得分:1)

您可以对两个查询做一个解释计划。 解释[你​​的sql]的计划; select * from table(dbms_xplan.display);

优化器会告诉不同计划之间的差异。

在我看来,第一个查询必须使用嵌套循环并遍历centros中的每一行并评估子查询中的每个记录以将其过滤掉。

第二个查询将在这两个表之间进行散列连接,并执行两次读取然后连接。这工作要少得多。

答案 1 :(得分:0)

你只是尝试使用全局临时表概念,在临时表中插入子qry的结果集,然后使用select * from temp table或直接将它与你的主qry连接。

我相信,即使我有这个问题,这也会使你的表现提高很多倍。

如果你有任何疑问,请试着告诉我。

CREATE GLOBAL TEMPORARY TABLE my_temp_table (
  column1  NUMBER) ON COMMIT PRESERVE ROWS;

insert into my_temp_table 

  SELECT TO_NUMBER (dc.centro)
  FROM datos_centro dc, centros c
 WHERE TO_NUMBER (c.numcen) = TO_NUMBER (dc.centro)
   AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?)

答案 2 :(得分:0)

在子查询中引用中心是多余的。

尝试:

SELECT numcen
  FROM centros
 WHERE TO_NUMBER (centros.numcen) = TO_NUMBER (?)
    OR TO_NUMBER (centros.numcen) IN (
          SELECT TO_NUMBER (dc.centro)
            FROM datos_centro dc
             AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));

......或......

SELECT numcen
  FROM centros
 WHERE TO_NUMBER (centros.numcen) IN (
          SELECT TO_NUMBER (?)
            FROM dual
          UNION ALL
          SELECT TO_NUMBER (dc.centro)
            FROM datos_centro dc
             AND TO_NUMBER (dc.centro_superior) = TO_NUMBER (?));

如果你不需要那些TO_NUMBER()函数,那么就去除它们,或者在TO_NUMBER(centros.numcen)和TO_NUMBER(dc.centro_superior)上添加基于函数的索引。