2012-04-05 380 views
0

最近我一直在尝试将更多的WITH语句合并到我的Oracle SQL中,以创建更清晰,更高效的代码。但是,我仍然认为它实际上效率较低,但只有在某些情况下,这是令人沮丧的。Oracle:WITH语句执行速度很慢

一个例子是创建一个用于对电话号码进行排序的WITH语句。我希望它能够检索所有有效/有效电话号码中最好的。

下面是我使用排名的电话号码WITH语句的例子:

Select * From (
WITH 
PHONE_RANK as   
-- Description: Phone numbers with a RANK_NO generated based on importance. 
(
    Select 
     ID as ID, 
     PHONE_AREA || PHONE_NUMBER || PHONE_EXT as PHONE_NUMBER, 
     TELE_CODE as TELE_CODE, 
     PRIMARY_IND as PRIMARY_IND, 
    --Generate a RANK_NO 
     row_Number() over 
     (
      Partition By ID 
      Order By 
       ID, 
       Decode(PRIMARY_IND, 'Y',1, 2), 
       Decode(TELE_CODE, 'MA',1, 'PR',2, 'CA',3, 'CELL',4, 99) 
     ) as RANK_NO 
    From 
     SPRTELE 
    Where 
     STATUS_IND is null 
     and TELE_CODE in ('MA', 'PR') 
     and Length(PHONE_AREA || PHONE_NUMBER || PHONE_EXT) >= 7 
) 

Select SPRIDEN.ID, PHONE_NUMBER 
From SPRIDEN, PHONE_RANK --SPRIDEN contains basic info (name, id, etc) 
Where 
    SPRIDEN.CHANGE_IND is NULL 
    SPRIDEN.ID = PHONE_RANK.ID 
    and RANK_NO = 1 
) 

PHONE_RANK相当快,如果加入到SPRIDEN表运行。但是,当我尝试通过RANK_NO限制它时,运行需要更长的时间。

  • 无PHONE_RANK上的任何条件,它运行时间不到0.2秒。
  • and PHONE_RANK.RANK_NO = 1大约需要3.5秒。
  • 使用and PHONE_RANK.RANK_NO = 1时,它是更复杂的代码的一部分,它往往会缩放。

(开始编辑)

我已经使用子查询这个过程。速度非常好,而且他们对于电话号码也很体面。但是,由于最常见的数字是PR和MA,而其中一个或另一个可能不存在,所以我使用两个子查询来拉取每个数据。

我的“计划”很简单:根据主要指标和电话代码为每个学生/个人拉最佳记录。因此,如果只有PR或MA记录,我们仍然会得到一个结果,因为最好的结果将被提取。但是,有时不存在Phone MA或PR#,但是我们仍然希望学生信息,因此不得不限制主查询内部的查询并不理想(但第二个WITH语句应该能够处理该问题)。

最终,我想将结果应用到地址表,这与SPRTELE类似。子查询拉电话号码是好的,但使用单独的子查询来拉街,城市,州和邮编是不理想的。再次,我们必须同时拉PR和MA地址,以防其中一个或另一个不存在。

在我看来,Address和Phone表都设置得很差,因为可以有任何Phone/Address类型(TELE_CODE,ATYP_CODE)的倍数,并且每种类型的记录都可以是活动的。另外,数据不能很好地保持(这将是一个野兽来维护它)。

对于SPRTELE表的字段(索引加星号):

*ID (004000, 123456, etc) 
*SEQNO (1, 2... n) 
*TELE_CODE (MA, PR, etc) 
ACTIVITY_DATE 
COMMENT 
CTRY_CODE_PHONE 
DATA_ORIGIN 
INTL_ACCESS 
PHONE_AREA 
PHONE_EXT 
PHONE_NUMBER 
PRIMARY_IND 
ADDR_SEQNO 
ATYP_CODE 
STATUS_IND 
UNLIST_IND 
USER_ID 

如果它是有用的,这里是我使用的电话号码的子查询。我还包括一个永久电话号码(TELE_CODE ='PR')。

(
Select PHONE_AREA || PHONE_NUMBER || PHONE_EXT 
From SPRTELE 
Where 
    ID = S1.ID 
    and STATUS_IND is Null 
    and TELE_CODE = 'MA' 
    and SEQNO = 
    (
     Select Max(SEQNO) 
     From SPRTELE 
     Where 
      ID = S1.ID 
      and STATUS_IND is Null 
      and TELE_CODE = 'MA' 
    ) 
) as MA_Phone 

此外,这些是用于拉一个地址的子查询。再次,我必须使用两个来获得MA和PR地址类型,以防万一丢失。

--MAILING STREET ADDRESS 
(
    Select STREET_LINE1 || ' ' || STREET_LINE2 || ' '|| STREET_LINE3 
    From SPRADDR S2 
    Where 
     S2.ID = S1.ID 
     and ATYP_CODE = 'MA' 
     and STATUS_IND is NULL 
     and SEQNO = 
     (
      Select MAX(SEQNO) 
      From SPRADDR S2 
      Where 
       S2.ID = S1.ID 
       and ATYP_CODE = 'MA' 
       and STATUS_IND is NULL 
     ) 
) as MA_Street, 

--MAILING CITY STATE ZIP 
(
    Select CITY || ', ' || STAT_CODE || ' ' || ZIP 
    From SPRADDR S2 
    Where 
     S2.ID = S1.ID 
     and ATYP_CODE = 'MA' 
     and STATUS_IND is NULL 
     and SEQNO = 
     (
      Select MAX(SEQNO) 
      From SPRADDR S2 
      Where 
       S2.ID = S1.ID 
       and ATYP_CODE = 'MA' 
       and STATUS_IND is NULL 
     ) 
) as MA_Address, 

(完编辑)

与以下将是伟大的任何帮助:

  1. 为什么会选择 'RANK_NO = 1' 造成这种缺乏的表现?它是WITH语句,Partition By还是别的?
  2. 难道还有比使用“PARTITION BY”,然后选择RANK_NO = 1让高层的电话号码一个更好的办法?
  3. 有关改进上述代码的建议。
  4. 其他建议。
+0

什么是表结构?什么是索引?最后,什么是完整的SQL语句,因为这不起作用...特别是索引;没有人是神奇的,我们不能帮助没有所有的信息 – Ben 2012-04-05 21:02:52

+0

除了本说什么之外:你是否尝试过“un” - 将WITH子句中的查询重构回到主查询中(作为子查询,很可能)在这种情况下它的表现如何? – FrustratedWithFormsDesigner 2012-04-05 21:05:16

+0

使用查询分析器准确告诉您Oracle为每个查询执行的操作。没有必要让我们猜测。 – Josh 2012-04-05 22:28:00

回答

1

在此查询中,硬(昂贵)操作是获取rank - row_number函数 - 这需要(有时在查询中不显式)排序。

  1. 也许这是因为当你不写RANK_NO = 1,则不要使用RANK_NO列elswere,所以Oracle并不需要计算。

  2. 您可以订购内部查询,并在外部queryes,使用ROWNUM,但你不能有分区。你有一个分区,一个单元1,一个单元2,等等。

  3. 如果你可以过滤你从SPRTELE表中获取行,你会得到更好的速度。几行 - >更好的速度。
  4. 你应该看到整个解释计划,以改善某些事情。 发布查询的解释计划。
+0

感谢您提供此信息。当实际使用该列时,SQL仅运行分区很有意义。这是辉煌的。至于解释计划,你想在哪里发布它?你想要所有的列还是只有特定的列? – Phillip 2012-04-06 15:32:33

+0

当我有一段时间时,我会阅读你添加的问题。 – 2012-04-07 10:21:49

+0

听起来不错。感谢您的帮助! – Phillip 2012-04-10 14:06:31