最近,我一直在尝试将更多 WITH 语句合并到我的 Oracle SQL 中,以创建更清洁、更高效的代码。但是,我仍然觉得它实际上效率较低,但仅在某些条件下,这令人沮丧。
一个示例是为电话号码排名而创建的 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
)
如果加入到 SPRIDEN 表中,PHONE_RANK 运行得相当快。但是,当我尝试通过 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,
(结束编辑)
以下任何帮助都会很棒:
- 为什么选择“RANK_NO = 1”会导致性能如此低下?是 WITH 语句、Partition By 还是其他?
 - 有没有比使用“Partition By”然后选择 RANK_NO = 1 来获得最高电话号码更好的方法?
 - 改进上述代码的建议。
 - 任何其他建议。