既然你基本上做一個全表掃描(就像你的查詢從該表中提取所有數據,不包括不會有第一次被,中間或姓氏部分幾行),您可能要考慮編寫查詢,以便它只是返回一個稍微不同的格式的數據,如:
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行而不是一個每個名稱結束,但它可能爲了讓你的客戶端代碼一起滾動,這些都是微不足道的。您還可以通過使用解碼,GROUP BY和max滾動3行成一個:
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路聯接。如果您將表格設置爲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),事實證明你與散列連接原來的查詢是最快的(27與106一致獲取了我指定的約束)。
在第三方面,如果上面的查詢用於填充使用光標滾動結果集的GUI(例如,您只會看到結果集的前N行 - 最初由此轉載添加一個「和行數」),我的版本的查詢再次變得快速 - 非常快(4個一致的獲取與417)。
故事的寓意在於,它確實取決於您如何訪問數據。對整個結果集運行良好的查詢在針對不同子集應用時可能會更糟糕。
我會考慮一個不同的設計,其中所有名稱部分都是表中person_id是PK的列。 – 2009-08-13 16:24:21
通過將每個部分放在它自己的表中,您可能會發現加速 - 由於您檢索數據的方式,您總是需要將一個表中的多行連接在一起。看起來很直觀,如果他們在自己的位置,找到每個部分會更容易,而不是讓他們混在一張桌子裏。否則,史蒂夫的答案可能是最好的。 – 2009-08-14 14:23:11