2009-10-15 80 views
2

我有一個分區表,如下所示:甲骨文拒絕使用索引

create table demo (
    ID NUMBER(22) not null, 
    TS TIMESTAMP not null, 
    KEY VARCHAR2(5) not null, 
    ...lots more columns... 
) 

分區是在TS列(每年一個分區)。

因爲我通過時間戳搜索了很多,我創建了一個組合索引:

create index demo.x1 on demo (ts, key); 

查詢看起來是這樣的:

select * 
from demo t 
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS') 

我也嘗試添加and t.KEY = '00101'但不幫幫我。

EXPLAIN PLANTABLE ACCESSFULL

# Operation   Options Object Mode   Cost Bytes Cardinality 
0 SELECT STATEMENT    ALL_ROWS  583804 287145 2127 
1 PARTITION RANGE ALL       583804 287145 2127 
2 TABLE ACCESS  FULL HEADER ANALYZED  583804 287145 2127 

指數沒有提到。什麼可能是錯的?

[編輯]出於某種原因,甲骨文完全錯誤的操作成本。那張桌子裏有112萬行。全面掃描單個分區的成本應該是2000萬,而不是600'000。這就是爲什麼它甚至忽略優化器提示。

[編輯2]在我的測試中,我跑過了這個令人費解的結果。當我運行這個select

select tx_ts 
from kt.header 
where tx_ts = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS') 

我得到這樣的解釋計劃:

0 SELECT STATEMENT        ALL_ROWS 152 15616 1952 
1 PARTITION RANGE ALL         152 15616 1952 
2 INDEX    FAST FULL SCAN HEADERX2 ANALYZED 152 15616 1952 

所以,當我把自己限制在索引列的結果select,甲骨文決定使用索引。當我想要獲得所有列時,我必須等待全表掃描。這裏發生了什麼?

[EDIT2]找到它;請參閱下面的答案。

+1

有一個你正在運行EXPLAIN PLAN的查詢的例子嗎? – 2009-10-15 16:04:57

+0

表中有多少數據?另外,它是真的在做一個全表掃描,或者只是掃描一個特定的分區? – 2009-10-15 16:10:30

+0

在這裏,你去。當我讀它時,它會掃描一切(全部1.1億行)。 – 2009-10-16 09:26:52

回答

4

好吧,這是我犯的一個錯誤:列有型DATE,不TIMESTAMP。由於我使用了to_timestamp(),Oracle認爲無法使用索引。

+0

非常感謝。同樣的問題在這裏。最好的問候。 – 2017-10-04 19:05:08

1

你的數據是否是最新的?無效的統計信息可能意味着oracle認爲全表掃描比使用索引更快。您是否在查詢中使用了任何提示,可能會告訴oracle進行全面掃描?

您能否向我們提供完整的查詢和解釋計劃結果?

編輯:亞倫,您可以使用「dbms_stats.gather_schema_stats」或「dbms_stats.gather_table_stats」命令更新統計信息。有關這些命令的更多信息,請參閱here。這將更新指定的模式或表的所有相關統計信息。 Oracle基於成本的優化器將使用統計信息來確定選擇哪個執行計劃。它從不使用實際的表格大小。當表格的大小發生顯着變化時(+/- 10%左右),您需要重新更新統計信息。

另一件事。當您使用複合索引時,您需要指定查詢中索引中使用的所有列,以便優化器考慮索引(我認爲您需要按照相同的順序指定它們,儘管我可能錯了那已經有一段時間了,因爲我看了這個東西)

+0

我編輯了我的問題。該索引應該是最新的,因爲我剛剛刪除並重新創建它。我如何檢查統計信息? – 2009-10-16 09:25:24

1

在您發佈的「CREATE INDEX ...」語句的轉錄中可能只是存在一個錯字,但是您確定您確實已經創建了索引?

給我們統計的一些第一通主意,使用這些查詢:

select table_name, num_rows 
    from user_tables 
    where table_name = 'DEMO'; 

select table_name, num_rows 
    from user_tab_partitions 
    where table_name = 'DEMO'; 

select index_name, num_rows from user_indexes      
    where table_name in     
    (select table_name         
     from user_tables where table_name = 'DEMO'); 

此外,究竟你是如何生成解釋計劃?如果啓用跟蹤,您是否有權訪問數據庫主機以檢索跟蹤文件?

正如我所評論的那樣,查看查詢的實際執行的跟蹤會很好。既然你已經表明你可以訪問數據庫主機的文件系統,運行SQL腳本,(在同一個會話)發出以下內容:

alter session set sql_trace=true; 
select /* THIS IS THE TRACE */ 
* 
from demo t 
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS'); 
exit 
  • 腳本退出後,找出 其中跟蹤文件目錄是由 這個查詢:

    從v $ parameter中選擇值其中name ='user_dump_dest';

  • 使用任何搜索工具 提供給您要查找的文件 包含字符串「這是 TRACE」

  • 流程/輪廓跟蹤文件 發出操作系統命令TKPROF traceFileName.trc tkprof.out

檢查這個文件 - 你會看到一些開銷信息,但會有一個個分組在詳細的實際執行計劃和查詢統計。如果你看到這個信息相同的結果,則接下來的一步是添加另一份聲明爲什麼在Oracle CBO是忽略了索引,將轉儲信息(第一「alter session的」後):

ALTER SESSION SET EVENTS='10053 trace name context forever, level 1'; 
+0

第一個查詢返回107,640,377,第二個查詢將該數字分成五個分區。最後一個返回索引112,153,440。 – 2009-10-16 13:01:23

+0

有一點可能會產生影響:我創建了比我需要的更多的分區(我已經在接下來的20年中創建了分區)。到目前爲止這些都是空的(所以我有五個分區,行數大致相同,二十個分別爲0行)。 – 2009-10-16 13:02:50

+0

這是一個好消息 - 看起來你可以使用基本的統計數據。正如我所提到的,我認爲看到一個被跟蹤的執行可能很好 - 你能訪問數據庫主機文件系統嗎? – dpbradley 2009-10-16 13:05:30

1

我m並不是真正的分區專家,但我想這裏發生的事情是,你已經創建了一個全局索引 - 一個包含所有分區中的行的索引。因此,優化器必須在兩個互斥的訪問路徑之間進行選擇:(A)索引範圍掃描或(B)分區修剪。我相信PARTITION RANGE操作表示它已經選擇了B.

正如其他人所建議的那樣更新統計信息可能會改變行爲。當您刪除並重新創建索引時,將丟棄索引存在的所有統計信息。

將索引創建爲UNIQUE(如果時間戳和鍵唯一標識一行)將是一個好主意,並且可能會改變行爲。

但是,我認爲真正的「修復」是您應該改爲創建本地索引 - 每個分區上的單獨索引。這應該使優化器能夠進行分區修剪,然後進行索引查找。老實說,我不確定這樣做的確切語法是什麼。也許你只是使用單獨的分區名稱明確地在每個分區上創建索引。

+1

對於那些想了解更多信息的人,請查看http://download.oracle.com/docs/cd/B10501_01/server.920/a96524/c12parti.htm#459801。有關如何創建本地分區索引的示例,請搜索「本地索引創建的示例」。 – 2009-10-16 14:03:53

+0

基本上,在列列表之後添加單詞「local」:'在演示(ts,鍵)上創建索引demo.x1 LOCAL' – 2009-10-16 14:19:21

+0

我已經重新創建索引,但EXPLAIN PLAN的結果不會更改。我檢查了'USER_INDEXES'的內容,並且新的索引在'PARTITIONED'列中帶有'YES'。這開始激怒我:) – 2009-10-16 14:21:04

1

如果一切都失敗了,你可以嘗試一個優化提示:

select /*+ index(demo.demo demo.x1) */ * 
from demo t 
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS') 
+0

感謝提示.Oracle不會被打擾:(它固執地堅持全表掃描 – 2009-10-16 15:14:07

+0

但是當我添加第二個索引列(鍵)時,它突然生效! – 2009-10-16 15:15:34