最近、よりクリーンで効率的なコードを作成するために、より多くの WITH ステートメントを Oracle SQL に取り込もうとしています。ただし、実際には効率が悪いと感じ続けていますが、それは特定の条件下でのみであり、イライラしています.
1 つの例は、電話番号をランク付けするために作成された 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 であり、どちらか一方が存在しない可能性があるため、2 つのサブクエリを使用してそれぞれをプルします。
私の「計画」は単純です。主な指標と電話番号に基づいて、各生徒/個人の最高の記録を引き出します。したがって、PR レコードまたは MA レコードのみがある場合でも、最良のものが引き出されるため、結果が得られます。ただし、Phone MA または PR # が存在しない場合もありますが、それでも学生の情報が必要なため、メイン クエリ内でクエリを制限する必要があるのは理想的ではありません (ただし、2 つ目の WITH ステートメントで対応できるはずです)。
最終的には、結果を SPRTELE に似た Address テーブルに適用したいと思います。電話番号をプルするサブクエリは問題ありませんが、別のサブクエリを使用して番地、都市、州、郵便番号をプルするのは理想的ではありません。また、どちらか一方が存在しない場合に備えて、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') の 1 つも含めます。
(
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
また、これらは 1 つのアドレスを取得するために使用されるサブクエリです。繰り返しになりますが、MA と PR の両方のアドレス タイプを取得するには、どちらか一方が欠落している場合に備えて、2 つを使用する必要があります。
--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 を選択して一番上の電話番号を取得するよりも良い方法はありますか?
- 上記のコードを改善するための提案。
- その他の提案。