国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

創建索引對SQL語句執行的影響

2024-07-21 02:13:16
字體:
來源:轉載
供稿:網友

一、創建索引對執行計劃的影響

在sql開始執行之前,oracle會確定sql語句的執行計劃,并按照執行計劃的步驟訪問相應的表和索引。

一旦執行計劃確定下來,oracle會按照這個執行計劃完成sql語句的執行,在sql語句執行開始之后建立的索引不會改變sql語句的執行計劃。

因此,創建索引不會對執行計劃有任何的影響,也就不會對運行中的sql語句有影響。下面通過一個例子簡單驗證一下:

sql> create table test (id number, fid number, name varchar2(30), bid_columns char(2000));

table created.

sql> insert into test values (1, 0, 'object', '0');

1 row created.

sql> insert into test values (2, 1, 'table', '0');

1 row created.

sql> insert into test values (3, 1, 'index', '0');

1 row created.

sql> insert into test values (4, 1, 'view', '0');

1 row created.

sql> insert into test values (5, 1, 'synonym', '0');

1 row created.

sql> insert into test values (6, 1, 'source', '0');

1 row created.

sql> insert into test select 20000+rownum, 2, table_name, '0' from dba_tables;

874 rows created.

sql> insert into test select 30000+rownum, 3, index_name, '0' from dba_indexes;

1074 rows created.

sql> insert into test select 40000+rownum, 4, view_name, '0' from dba_views;

2929 rows created.

sql> insert into test select 50000+rownum, 5, table_name, '0' from dba_synonyms;

2437 rows created.

sql> insert into test select 60000+rownum, 6, name, '0' from dba_source;

99717 rows created.

sql> commit;

commit complete.

sql> set timing on

sql> select count(*) from test

2 start with id = 1

3 connect by prior id = fid;

count(*)

----------

107037

elapsed: 00:02:03.84


構造一個樹狀查詢,然后記錄這個樹狀查詢的運行時間。

sql> select count(*) from test

2 start with id = 1

3 connect by prior id = fid;

count(*)

----------

107037

elapsed: 00:05:26.15

再次運行查詢,在查詢運行開始,馬上在另一個session創建索引。通過觀察執行時間可以發現,創建索引不會對運行中的sql語句帶來性能提升,而且很可能由于系統資源的爭用造成查詢速度變慢。如果在io分布的比較合理的系統中,可以看到,創建索引可以很快完成,而且隨后執行同樣的查詢由于會使用索引,也會很快的返回結構,但是索引的創建不會加快已經處于運行狀態的語句的速度。

session2:

sql> set timing on

sql> create index ind_test_id on test(id) tablespace users;

索引已創建。

已用時間:000: 01: 56.92

sql> create index ind_test_fid on test(fid) tablespace users;

索引已創建。

已用時間: 00: 02: 00.57

建立索引后,同樣的查詢速度得到明顯的提升。

sql> select count(*) from test

2 start with id = 1

3 connect by prior id = fid;

count(*)

----------

107037

已用時間: 00: 01: 02.11

上面建立兩個索引的語句和查詢語句是在單獨的session2上運行的。session2上的三個操作——創建兩個索引和執行相同的查詢語句——都執行完成了,而第一個會話的的運行結果仍然沒有返回。

二、創建索引對oracle內部機制的影響

上面通過一個簡單的例子說明,創建索引不會改變已經運行的sql的執行計劃。但是并不是說,創建索引不能給已經運行的sql語句帶來性能的提升。

下面看一個比較特殊的例子:

sql> create table test as select rownum id, a.* from dba_objects a;

表已創建。

sql> create table test1 as select rownum id, rownum fid, a.* from dba_synonyms a;

表已創建。

sql> alter table test add constraint pk_test primary key (id);

表已更改。

sql> alter table test1 add constraint fk_test1_fid foreign key (fid) references test(id);

表已更改。

sql> insert into test1 select * from test1;

已創建1616行。

sql> insert into test1 select * from test1;

已創建3232行。

sql> insert into test1 select * from test1;

已創建6464行。

sql> insert into test1 select * from test1;

已創建12928行。

sql> insert into test1 select * from test1;

已創建25856行。

sql> commit;

提交完成。

sql> delete test1;

已刪除51712行。

sql> commit;

提交完成。

sql> set timing on

sql> delete test;

已刪除6208行。

已用時間: 00: 00: 17.03

sql> rollback;

回退已完成。

已用時間: 00: 00: 00.06


構造兩張表,test1的fid建立了參考test表id列的外鍵。但是這里并沒有在外鍵列上建立索引。

向test和test1表中填入一定數據量的數據,開始測試。這里測試的是刪除test表的執行時間。首先將test1用delete命令刪除,提交后計算刪除test表的時間,大約需要17秒,然后將數據回滾。

下面準備進行第二次刪除測試,所不同的是,在刪除操作開始后,馬上在另一個session中給外鍵列增加索引,通過測試可以發現,幾乎在索引創建完的同時,第一個session就返回了結果,刪除需要的時間縮短到了3秒。

第一個session的刪除語句:

sql> delete test;

已刪除6208行。

已用時間:? 00: 00: 03.00

第二個session的索引創建語句:

sql> create index ind_test1_fid on test1(fid);

索引已創建

這個測試中索引的創建影響到了已經在運行的sql語句,并明顯地提高了執行效率。這個現象和上一篇文章中描述的觀點并不沖突。對于用戶發出的sql語句,oracle的執行計劃是不變的,但是為了執行用戶發出的sql語句,oracle在內部做了大量的操作,包括權限的檢查、語法的檢查、目標對象是否存在,以及維護數據的完整性等等。這個例子中,用戶發出的sql語句的執行計劃沒有改變,發生改變的是oracle內部維護操作語句的執行計劃。

如果在第一個session執行delete操作的同時,通過下面的sql語句檢查第一個session正在運行的語句,會發現下面的結果(9i及以前版本,如果是10g,則只能看到delete test)。

sql> select sql_text from v$session a, v$sql b

2 where a.sql_hash_value = b.hash_value

3 and a.sql_address = b.address

4 and a.sid = 17;

sql_text

----------------------------------------------------------------------------

select /**//*+ all_rows */ count(1) from "yangtk"."test1" where "fid" = :1

這個sql語句就是oracle用來維護完整性的內部sql。

回想一下我們的例子,建立了外鍵,但是沒有建立索引。當每刪除一條test的記錄,oracle都要檢查這個主鍵是否在test1中被引用。由于沒有索引,oracle只能通過全表掃描來尋找test1中的記錄。雖然test1沒有記錄,但是刪除test時使用的是delete而不是truncate,因此test1的高水位線并沒有下降,也就是說,每刪除一條test的記錄,都需要全表掃描一張擁有5萬條數據的表,這就是為什么那個delete操作執行很慢的原因。

而我們建立的索引正是加快了這個步驟,oracle內部維護的sql語句在索引可用后選擇了索引掃描,因此delete操作在索引創建后迅速返回。

三、小結

創建索引對于用戶已發出的正在運行的sql不會帶來性能的提升。這是由于用戶執行的語句要按照執行計劃來運行,而執行計劃在運行開始的時候就確定下來了,且不會在sql語句的運行過程中發生變化。

對于sql執行過程中,oracle內部執行的用于維護的sql語句,是有可能從新創建的索引中獲得性能提升的。

菜鳥學堂:
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 枣强县| 明溪县| 昌都县| 乡宁县| 右玉县| 仁寿县| 浦东新区| 唐河县| 岑溪市| 庆城县| 德昌县| 治多县| 台南县| 西盟| 荃湾区| 清河县| 兴隆县| 衡水市| 百色市| 景谷| 获嘉县| 米泉市| 汤阴县| 沅陵县| 沈阳市| 香港 | 大英县| 子长县| 金华市| 杭锦后旗| 沂源县| 蒙山县| 巨野县| 化州市| 湛江市| 盘锦市| 泰州市| 双柏县| 浙江省| 福州市| 凌云县|