我有一個包含大約 1800 萬條記錄的 Oracle 表。我必須在一個查詢中讀取整個表,因為所有記錄都是在一個日期中創建的。所以,首先我在四列上定義索引,我使用這個命令對它們進行查詢:
CREATE INDEX test_etl_index ON test_table(date,c_num,obc,bu)
創建索引后,我必須對c_num,obc,bu的每一列使用此查詢。查詢如下:
Select date,c_num,pd,pds,uc,obc,t_id,da,ca,db,time,ibc,lc,lt,STS,wd,bu
from test_table
where date='20170628'
and c_num in (select key from c_g where g_id=1)
但是,對于每一列,查詢大約需要 8 分鐘,這非常慢。
請指導我如何更改查詢以獲得更好的性能?
非常感謝任何幫助。
uj5u.com熱心網友回復:
根據您提供的資訊,幾乎無法提供任何建議。
除了 - 正如所推薦的 - 修復DATE列的資料型別,因為將日期存盤為字串會真正混淆優化器。
預期的設定取決于您的資料,這里有一些提示。
DATE 列是選擇性的
如果您的謂詞date='20170628'(或更好的col_date = date'2017-06-28)只回傳很少的記錄,您將從該列的索引中受益。
create index test_table_idx on test_table(col_date);
您可以期待如下的執行計劃
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 472 | 5 (0)| 00:00:01 |
|* 1 | HASH JOIN SEMI | | 4 | 472 | 5 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| TEST_TABLE | 10 | 1120 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | TEST_TABLE_IDX | 10 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | C_G | 3 | 18 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("C_NUM"="KEY")
3 - access("COL_DATE"=TO_DATE(' 2002-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
4 - filter("G_ID"=1)
請注意,Oracle在hash join semi中重寫了您的,因此不需要手動查詢重寫。in (subquery)
C_NUM 是選擇性的
相反,如果謂詞c_num in (...回傳很少的記錄,則在c_num列上定義一個索引。
create index test_table_idx2 on test_table(c_num);
您可以期待如下的執行計劃
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 480 | 28 (4)| 00:00:01 |
| 1 | NESTED LOOPS | | 4 | 480 | 28 (4)| 00:00:01 |
| 2 | NESTED LOOPS | | 20 | 480 | 28 (4)| 00:00:01 |
| 3 | SORT UNIQUE | | 3 | 18 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | C_G | 3 | 18 | 3 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | TEST_TABLE_IDX2 | 10 | | 2 (0)| 00:00:01 |
|* 6 | TABLE ACCESS BY INDEX ROWID| TEST_TABLE | 1 | 114 | 12 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("G_ID"=1)
5 - access("C_NUM"="KEY")
6 - filter("COL_DATE"=TO_DATE(' 2000-01-02 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
沒有選擇性
如果以上都不成立,忘記索引,你應該會看到一個 HASH JOIN SEMI,它不應該在 18M 表上花費太多時間
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 27273 | 3142K| 4516 (1)| 00:00:01 |
|* 1 | HASH JOIN RIGHT SEMI| | 27273 | 3142K| 4516 (1)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | C_G | 3 | 18 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | TEST_TABLE | 90909 | 9943K| 4512 (1)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("C_NUM"="KEY")
2 - filter("G_ID"=1)
3 - filter("COL_DATE"=TO_DATE(' 2000-01-02 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
重要的一點是學習如何獲取查詢的執行計劃,如何閱讀它以及如何理解瓶頸在哪里。
uj5u.com熱心網友回復:
僅在 date 和 c_num 列上創建索引,而不是 (date,c_num,obc,bu) 或在 date 和 c_num 上創建另一個索引并呼叫此 idx2
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/421794.html
標籤:
