最近,我一直在尝试将更多 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 来获得最高电话号码更好的方法?
- 改进上述代码的建议。
- 任何其他建议。