2015-10-22 67 views
2

我有一個擁有超過1000萬行的表。我創建該表上的一個新列,然後試圖建立索引:在Oracle中爲大表創建新索引

create index myTable_idx_myColumn on myTable(myColumn); 

該查詢大約一個小時後超時。然後我用NOLOGGING選項重試它,並在大約一個小時後成功完成。

問題解決了吧?不幸的是,這不僅僅是開發數據庫。 prod數據庫有超過2500萬行,所以理想情況下,我希望在創建索引之前找到更快的解決方案,以避免不必要的停機時間。

我覺得很奇怪的是,據我瞭解,Oracle默認不包含null值(這是我想要的)。對我來說,這意味着它應該創建一個空白索引,因爲索引創建時新列中的所有值都是null。我得到它需要檢查所有的1個千萬行,以確保它們null,但即使這樣似乎並不像它應該採取任何接近一個小時......

是否有添加的快捷方式索引到一個新的列(即所有值爲null)在一張大桌子上?

+0

爲什麼你需要索引null null列?如果你想要索引中的所有行(rowid),那麼你需要創建複合索引,其中至少有一列不爲空。 – clq

+0

@clq這些值僅爲空,因爲它是全新的列。新行將獲得值,並且基於這些值進行查詢將很常見,因爲它是另一個表的外鍵。 – Briguy37

+0

有許多人認爲你可以做。索引需要很長時間才能創建的原因肯定是有原因的。 25M不是很多。最好,如果你問你的dba。 :)一個技術opton可能是運行並行索引創建。一個非技術性的選擇是安排創建索引語句並在週末運行。 – clq

回答

1

有辦法使其更快,但他們可能沒有必要。

1000萬行是一個相對較小的數字。儘管如果行很寬,情況可能會有所不同。對於性能問題,通常知道段大小比行數更好。分段大小和硬件知識將幫助您做出非常粗略的估計。例如,「表格爲100GB,SAN以100MB /秒讀取單線程,因此掃描表格需要17分鐘......」。

--Find the segment size in gigabytes. 
--No matter how many rows there are this may be the amount of I/O processed. 
select sum(bytes)/1024/1024/1024 gb 
from dba_segments 
where segment_name = 'MYTABLE'; 

在這個簡單的例子,10個百萬行是在5秒鐘內創建我的電腦上。

--Create table. 
drop table myTable; 
create table myTable(id number, myColumn varchar2(100)) nologging; 

--Insert 10 million rows. Takes 9 seconds on my PC. 
begin 
    for i in 1 .. 100 loop 
     insert /*+ append */ into myTable 
      select level, null from dual connect by level <= 100000; 
     commit; 
    end loop; 
end; 
/

--Create index. Takes 5 seconds on my PC. 
create index myTable_idx_myColumn on myTable(myColumn); 

那麼你的機器上發生了什麼?爲了找出問題,首先需要找到CREATE INDEX ...語句的SQL_ID。在建立索引時,運行:

--Find the SQL_ID. 
select sql_id, sql_text, elapsed_time/1000000 seconds 
from v$sql 
where users_executing > 0 
order by seconds desc; 

有很多方法可以從這裏開始,我更喜歡SQL Monitoring。如果報表正在運行或正在「近期」運行,則監視數據應該仍在。將SQL_ID插入到此SQL語句中以獲取報告:

--Generate SQL Monitoring report. 
--(This feature requires licensing, but if this is the first time you use it, it's 
-- reasonable to consider this "testing". Buy it if you like it.) 
select dbms_sqltune.report_sql_monitor('gb7tu2jpwng3q') from dual; 

報告中有大量數據。這需要一段時間才能理解,但通常它會包含解決這些問題所需的大部分內容。首先,看一下活動(%) - 哪一步最長?然後看看細節 - 它在等什麼?看看讀寫字節,它們對於硬件是否合理?

SQL Monitoring Report 

SQL Text 
------------------------------ 
create index myTable_idx_myColumn on myTable(myColumn) 

Global Information 
------------------------------ 
Status    : DONE        
Instance ID   : 1         
Session    : JHELLER (133:56633)    
SQL ID    : gb7tu2jpwng3q      
SQL Execution ID : 16777216       
Execution Started : 10/23/2015 00:34:32    
First Refresh Time : 10/23/2015 00:34:36    
Last Refresh Time : 10/23/2015 00:34:37    
Duration   : 5s         
Module/Action  : PL/SQL Developer/SQL Window - New 
Service    : orcl12        
Program    : plsqldev.exe      

Global Stats 
================================================================================================ 
| Elapsed | Cpu | IO | Application | PL/SQL | Buffer | Read | Read | Write | Write | 
| Time(s) | Time(s) | Waits(s) | Waits(s) | Time(s) | Gets | Reqs | Bytes | Reqs | Bytes | 
================================================================================================ 
| 4.72 | 2.67 |  1.84 |  0.21 | 0.00 | 15594 | 3904 | 312MB | 795 | 192MB | 
================================================================================================ 

SQL Plan Monitoring Details (Plan Hash Value=564701026) 
======================================================================================================================================================================================================== 
| Id |  Operation   |   Name   | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Write | Write | Mem | Temp | Activity |  Activity Detail  | 
| |       |      | (Estim) |  | Active(s) | Active |  | (Actual) | Reqs | Bytes | Reqs | Bytes | (Max) | (Max) | (%) |  (# samples)   | 
======================================================================================================================================================================================================== 
| 0 | CREATE INDEX STATEMENT |      |   |  |   2 |  +4 |  1 |  1 |  |  |  |  |  |  |   |       | 
| 1 | INDEX BUILD NON UNIQUE | MYTABLE_IDX_MYCOLUMN |   |  |   2 |  +4 |  1 |  1 |  |  |  |  |  |  | 25.00 | Cpu (1)     | 
| 2 | SORT CREATE INDEX  |      | 100K |  |   4 |  +2 |  1 |  10M | 3656 | 192MB | 795 | 192MB | 75M | 202M | 75.00 | Cpu (2)     | 
| |       |      |   |  |   |  |  |   |  |  |  |  |  |  |   | direct path write temp (1) | 
| 3 |  TABLE ACCESS FULL | MYTABLE    | 100K | 46 |   1 |  +4 |  1 |  10M | 248 | 120MB |  |  |  |  |   |       | 
======================================================================================================================================================================================================== 

我希望你會看到一些「奇怪的」事件。也許某種表鎖,因爲其他進程正在鎖定表。

如果這只是一張巨大的表格,需要數小時才能閱讀,那麼並行可能會有所幫助。這是使其工作的最簡單方法。調整並行性可能很困難,但如果你很幸運並且一切都配置合理,只需添加關鍵字parallel即可。

--Create index in parallel. 
create index myTable_idx_myColumn on myTable(myColumn) parallel nologging; 
--Reset it to NOPARALLEL after it's done. 
alter index myTable_idx_myColumn noparallel; 
+0

非常感謝您的回覆!第一個操作的結果是該表大約爲9.5GB。但是,由於dbms_sqltune.report_sql_monitor無法從dbVisualizer(ORA-00904:「DBMS_SQLTUNE」,「REPORT_SQL_MONITOR」:無效標識符)工作,我無法直接訪問服務器,但我們的DBA表示他可以在下週看到它。我會盡力爲其他有類似問題的人提供最新信息。 – Briguy37