0

我有这个查询(在 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-200 毫秒。更重要的是,如果我运行query2并将其结果放入INquery1替换子查询中,结果是立即的。

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

那么,有没有办法改进第一个查询(query1)?我应该分成两部分吗?如果我替换ORUNION(更快),它会是相同的查询吗?

任何建议都将受到欢迎。谢谢和对不起我的英语。

4

3 回答 3

1

你可以对你的两个查询做一个解释计划。解释 [你的 sql] 的计划;从表中选择*(dbms_xplan.display);

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

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

第二个查询将在这两个表之间进行哈希连接,然后进行两次读取然后连接。这是少得多的工作。

于 2017-07-01T14:23:00.767 回答
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 (?)
于 2013-05-23T10:05:42.117 回答
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) 上添加基于函数的索引。

于 2013-05-23T12:53:52.280 回答