有辦法使其更快,但他們可能沒有必要。
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;
爲什麼你需要索引null null列?如果你想要索引中的所有行(rowid),那麼你需要創建複合索引,其中至少有一列不爲空。 – clq
@clq這些值僅爲空,因爲它是全新的列。新行將獲得值,並且基於這些值進行查詢將很常見,因爲它是另一個表的外鍵。 – Briguy37
有許多人認爲你可以做。索引需要很長時間才能創建的原因肯定是有原因的。 25M不是很多。最好,如果你問你的dba。 :)一個技術opton可能是運行並行索引創建。一個非技術性的選擇是安排創建索引語句並在週末運行。 – clq