それだけのような、わずかに異なる形式のデータを返すようにクエリを書くことを検討してください:
SELECT person_id
, name_part_id
, name_part
FROM NAME_PART
WHERE name_part_id IN (1, 2, 3)
ORDER BY person_id
, name_part_id;
もちろん、あなたが3行の代わりに、それぞれの名前に1つになってしまいますが、それはかもしれませんあなたのクライアントコードがこれらを一緒にロールすることは自明です。
SELECT person_id
, max(decode(name_part_id, 1, name_part, null)) first
, max(decode(name_part_id, 2, name_part, null)) middle
, max(decode(name_part_id, 3, name_part, null)) last
FROM NAME_PART
WHERE name_part_id IN (1, 2, 3)
GROUP BY person_id
ORDER BY person_id;
これは、元のクエリと同じ結果を生成します。これにより、3行を1つにまとめることができます。どちらのバージョンでは唯一参加する代わりに、3ウェイを扱うのは、一度(ソート付き)テーブルをスキャンします。 person_id索引の索引構成表を作成した場合は、ソート・ステップを保存します。
私は56150人とテーブルを使用してテストを実行し、ここでは結果の荒廃です:
オリジナルクエリ:
Execution Plan
----------------------------------------------------------
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 113K| 11M| | 1364 (2)|
|* 1 | HASH JOIN | | 113K| 11M| 2528K| 1364 (2)|
|* 2 | TABLE ACCESS FULL | NAME_PART | 56150 | 1864K| | 229 (3)|
|* 3 | HASH JOIN | | 79792 | 5298K| 2528K| 706 (2)|
|* 4 | TABLE ACCESS FULL| NAME_PART | 56150 | 1864K| | 229 (3)|
|* 5 | TABLE ACCESS FULL| NAME_PART | 56150 | 1864K| | 229 (3)|
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("FIRST_NAME"."PERSON_ID"="LAST_NAME"."PERSON_ID")
2 - filter("LAST_NAME"."NAME_PART_ID"=3)
3 - access("FIRST_NAME"."PERSON_ID"="MIDDLE_NAME"."PERSON_ID")
4 - filter("FIRST_NAME"."NAME_PART_ID"=1)
5 - filter("MIDDLE_NAME"."NAME_PART_ID"=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6740 consistent gets
0 physical reads
0 redo size
5298174 bytes sent via SQL*Net to client
26435 bytes received via SQL*Net from client
3745 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
56150 rows processed
マイクエリ#1(3行/人):
Execution Plan
----------------------------------------------------------
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 168K| 5593K| | 1776 (2)|
| 1 | SORT ORDER BY | | 168K| 5593K| 14M| 1776 (2)|
|* 2 | TABLE ACCESS FULL| NAME_PART | 168K| 5593K| | 230 (3)|
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("NAME_PART_ID"=1 OR "NAME_PART_ID"=2 OR "NAME_PART_ID"=3)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1005 consistent gets
0 physical reads
0 redo size
3799794 bytes sent via SQL*Net to client
78837 bytes received via SQL*Net from client
11231 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
168450 rows processed
マイクエリ#2(1行/人):
Execution Plan
----------------------------------------------------------
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 56150 | 1864K| | 1115 (3)|
| 1 | SORT GROUP BY | | 56150 | 1864K| 9728K| 1115 (3)|
|* 2 | TABLE ACCESS FULL| NAME_PART | 168K| 5593K| | 230 (3)|
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("NAME_PART_ID"=1 OR "NAME_PART_ID"=2 OR "NAME_PART_ID"=3)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1005 consistent gets
0 physical reads
0 redo size
5298159 bytes sent via SQL*Net to client
26435 bytes received via SQL*Net from client
3745 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
56150 rows processed
が判明、あなたはまだ少し速くそれを絞ることができます。 person_idインデックスを強制的に使用するためのヒントを追加して、ソートを回避しようとしました。私は別の10%をオフにノックして管理し、それは並べ替えているように見える、それはまだ:
SELECT /*+ index(name_part,NAME_PART_person_id) */ person_id
, max(decode(name_part_id, 1, name_part)) first
, max(decode(name_part_id, 2, name_part)) middle
, max(decode(name_part_id, 3, name_part)) last
FROM name_part
WHERE name_part_id IN (1, 2, 3)
GROUP BY person_id
ORDER BY person_id;
Execution Plan
----------------------------------------------------------
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 56150 | 1864K| | 3385 (1)|
| 1 | SORT GROUP BY | | 56150 | 1864K| 9728K| 3385 (1)|
| 2 | INLIST ITERATOR | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID | NAME_PART | 168K| 5593K| | 2500 (1)|
| 4 | BITMAP CONVERSION TO ROWIDS| | | | | |
|* 5 | BITMAP INDEX SINGLE VALUE | NAME_PART_NAME_PART_ID| | | | |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("NAME_PART_ID"=1 OR "NAME_PART_ID"=2 OR "NAME_PART_ID"=3)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
971 consistent gets
0 physical reads
0 redo size
5298159 bytes sent via SQL*Net to client
26435 bytes received via SQL*Net from client
3745 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
56150 rows processed
をしかし、上記の計画は、すべてあなたが全体のテーブルから選択しているという仮定に基づいています。あなたはPERSON_IDに基づいて結果を制限する場合(例えば、55968と56000の間PERSON_ID)、それはハッシュ参加すると、あなたの元のクエリが最速(一貫性のある106は、私は指定された制約のためになる27対)であることが判明しました。
上記のクエリを使用してカーソルを使用して結果セットをスクロールするGUIを作成している場合(結果セットの最初のN行のみが表示されます。 "and rowcount 50"述語)を追加すると、クエリの私のバージョンは再び高速になります(4つの一貫性のある取得と417)。
ストーリーの道徳は、あなたがデータへのアクセス方法に本当に正確に依存しているということです。異なるサブセットに対して適用すると、結果セット全体でうまく機能するクエリが悪化する可能性があります。
私は、すべての名前の部分がperson_idがPKである表の列である、別のデザインを考えています。 –
速度を上げるには、各パーツを独自のテーブルに入れることができます。データを取得する方法によって、常に1つのテーブルに複数の行が結合されている必要があります。彼らが自分の場所にいる場合、各パーツを見つけるのは簡単で、1つのテーブルで混乱させるのは直感的です。それ以外の場合は、スティーブの答えがおそらく最善です。 –