26
T i u câu l nh Oracle SQL – ph n 1: n n ư t ng c b n ơ T i u câu l nh là ch đ nâng cao, vì v y đ có th hi u đ c các k thu t t i u câu l nh Oracle SQL, chúng ta ốư ượ ốư c n tìm hi u m t s khái ni m c b n liên quan đ n lĩnh v c này, bài vi t này không nh m m c đích chuy n t i toàn ơ ế ế b ki n th c liên quan đ n t i u câu l nh SQL, bài vi t ch trình bày nh ng khái ni m quan tr ng nh t, đ giúp ế ế ốư ế nh ng đ c gi đã am hi u ki n trúc Oracle có th hi u đ c. ế ượ N n t ng c b n ơ Trình t x lý câu l nh SQL Oracle Server x lý câu l nh SQL theo trình t các b c sau: ướ 1. Open o Ng m đ nh khai báo và kh i t o Cursor cho câu l nh SQL 2. Parse o Ki m tra câu l nh đã th c hi n tr c đó ch a, n u có thì chuy n sang th c hi n b c 3 ướ ư ế ướ o Phân tích và ki m tra cú pháp câu l nh SQL o Ki m tra tính h p l và quy n truy c p đ n các đ i t ng d li u câu l nh tham chi u t i ế ượ ế o Xác đ nh “ s đ th c thi câu l nh SQL ơ ” t i u nh t ốư 3. Bind o Tìm và gán giá tr cho các bind-variable n u có ế 4. Execute o Th c thi các b c mô t trong “s đ th c thi câu l nh SQL” ướ ơ 5. Fetch o Chuy n k t qu v n i g i th c thi l nh ế ơ 6. Close o Ng m đ nh đóng Cursor cho câu l nh Trong các giai đo n x lý trên, giai đo n Parse chi m nhi u th i gian nh t. ế Công c t i u câu l nh SQL*Plus AUTOTRACE ư Ch c năng

Tối ưu-cau-lệnh-oracle-sql

Embed Size (px)

DESCRIPTION

Toi uu hoa cau lenh SQL

Citation preview

Page 1: Tối ưu-cau-lệnh-oracle-sql

T i u câu l nh Oracle SQL – ph n 1: n nố ư ệ ầ ề t ng c b nả ơ ảT i u câu l nh là ch đ nâng cao, vì v y đ có th hi u đ c các k thu t t i u câu l nh Oracle SQL, chúng taố ư ệ ủ ề ậ ể ể ể ượ ỹ ậ ố ư ệ c n tìm hi u m t s khái ni m c b n liên quan đ n lĩnh v c này, bài vi t này không nh m m c đích chuy n t i toànầ ể ộ ố ệ ơ ả ế ự ế ằ ụ ể ả b ki n th c liên quan đ n t i u câu l nh SQL, bài vi t ch trình bày nh ng khái ni m quan tr ng nh t, đ giúpộ ế ứ ế ố ư ệ ế ỉ ữ ệ ọ ấ ủ nh ng đ c gi đã am hi u ki n trúc Oracle có th hi u đ c. ữ ọ ả ể ế ể ể ượ

N n t ng c b n ề ả ơ ả

Trình t x lý câu l nh SQLự ử ệ

Oracle Server x lý câu l nh SQL theo trình t các b c sau:ử ệ ự ướ

1. Open o Ng m đ nh khai báo và kh i t o Cursor cho câu l nh SQLầ ị ở ạ ệ

2. Parse o Ki m tra câu l nh đã th c hi n tr c đó ch a, n u có thì chuy n sang th c hi n b c 3ể ệ ự ệ ướ ư ế ể ự ệ ướo Phân tích và ki m tra cú pháp câu l nh SQLể ệo Ki m tra tính h p l và quy n truy c p đ n các đ i t ng d li u câu l nh tham chi u t iể ợ ệ ề ậ ế ố ượ ữ ệ ệ ế ớo Xác đ nh “ị s đ th c thi câu l nh SQLơ ổ ự ệ ” t i u nh tố ư ấ

3. Bind o Tìm và gán giá tr cho các ị bind-variable n u cóế

4. Execute o Th c thi các b c mô t trong “s đ th c thi câu l nh SQL”ự ướ ả ơ ồ ự ệ

5. Fetch o Chuy n k t qu v n i g i th c thi l nhể ế ả ề ơ ọ ự ệ

6. Close o Ng m đ nh đóng Cursor cho câu l nhầ ị ệ

Trong các giai đo n x lý trên, giai đo n ạ ử ạ Parse chi m nhi u th i gian nh t.ế ề ờ ấ

Công c t i u câu l nh SQL*Plus AUTOTRACE ụ ố ư ệ

Ch c năngứ

Page 2: Tối ưu-cau-lệnh-oracle-sql

Thu th p thông tin mô t quá trình th c thi câu l nh SQL, th ng đ c dùng đ t i u câu l nh.ậ ả ự ệ ườ ượ ể ố ư ệ

Cài đ tặ

Đ s d ng đ y đ ch c năng c a công c này, c n t o Table tên PLAN_TABLE và gán nhóm quy n PLUSTRACE choể ử ụ ầ ủ ứ ủ ụ ầ ạ ề tài kho n mu n s d ng công c :ả ố ử ụ ụ

1. Dùng $ORACLE_HOME/rdbms/admin/utlxplan.sql đ t o PLAN_TABLEể ạ2. Dùng tài kho n DBA ch y mã l nh $ORACLE_HOME/sqlplus/admin/plustrce.sql đ t o nhóm quy nả ạ ệ ể ạ ề

PLUSTRACE.

Ví dụ

Quan sát k t qu t mã d n trên, ta th y công c AUTOTRACE g i v ba nhóm thông tin sau:ế ả ừ ẫ ấ ụ ử ề

1. K t qu câu l nhế ả ệ2. S đ trình t th c thi câu l nhơ ồ ự ự ệ3. Thông tin th ng kê chi phí tài nguyên c n dùng đ th c thi câu l nhố ầ ể ự ệ

Cách s d ngử ụ

Page 3: Tối ưu-cau-lệnh-oracle-sql

Cú pháp l nhệ Ý nghĩa

SET AUTOTRACE ON B t tính năng thu th p và hi n th thông tin đ y đậ ậ ể ị ầ ủ

SET AUTOTRACE OFF T t tính năng thu th p và hi n th thông tinắ ậ ể ị

SET AUTOTRACE ON EXPLAIN Hi n th k t qu và EP câu l nhể ị ế ả ệ

SET AUTOTRACE ON STATISTICS Hi n th k t qu và thông tin th ng kê câu l nhể ị ế ả ố ệ

SET AUTOTRACE TRACEONLY Hi n th EP và thông tin th ng kê, không hi n th k t qu câu l nhể ị ố ể ị ế ả ệ

SET AUTOTRACE TRACEONLY EXPLAIN Ch hi n th EPỉ ể ị

SET AUTOTRACE TRACEONLY STATISTICS Ch hi n th th ng kêỉ ể ị ố

S đ th c thi câu l nh SQL ơ ồ ự ệ

S đ th c thi câu l nh SQL (Execution Plan - EP) mô t th t các b c Oracle c n th c thi đ có đ c k t qu câuơ ồ ự ệ ả ứ ự ướ ầ ự ể ượ ế ả l nh nhanh nh t.ệ ấ

Ví d v EP c a câu l nh xem d li u trên hai Table CUSTOMERS và COUNTRIES:ụ ề ủ ệ ữ ệ

Oracle qui đ nh th t x lý các b c c a EP nh sau:ị ứ ự ử ướ ủ ư

1. B t đ u x lý t b c n m th t v phía bên ph i nh t, ti p theo là các b c đ ng k tr c nóắ ầ ử ừ ướ ằ ụ ề ả ấ ế ướ ứ ế ướ2. N u hai b c có cùng th t thì s x lý b c n m phía trên tr cế ướ ứ ự ẽ ử ướ ằ ướ

Nh v y, ta th y EP trên đ c x lý theo th t đ c đánh s bên ph i.ư ậ ấ ượ ử ứ ự ượ ố ả

M t EP đ y đ bao g m ba thành t sau: ph ng th c truy c p d li u, ph ng pháp JOIN và th t JOIN gi a haiộ ầ ủ ồ ố ươ ứ ậ ữ ệ ươ ứ ự ữ hay nhi u t p d li u.ề ậ ữ ệ

Ph ng th c truy c p d li uươ ứ ậ ữ ệ

Page 4: Tối ưu-cau-lệnh-oracle-sql

Xác đ nh cách th c truy c p v t lý đ n t ng dòng d li u c a Table, ví du m t s ph ng pháp truy c p d li uị ứ ậ ậ ế ừ ữ ệ ủ ộ ố ươ ậ ữ ệ Table ph bi n:ổ ế

• Truy c p theo cách đ c t ng dòng c a Table ( TABLE ACCESS (FULL) ): đ c toàn b dòng d li u c a Tableậ ọ ừ ủ ọ ộ ữ ệ ủ đ đ i sánh d li u, vì v y n u Table có kích th c l n thì ph ng th c truy c p này s chi m nhi u chi phíể ố ữ ệ ậ ế ướ ớ ươ ứ ậ ẽ ế ề IO. Tuy nhiên, cách truy c p này cho phép chúng ta có th c u hình đ c nhi u kh i d li u (Block) cho m tậ ể ấ ọ ề ố ữ ệ ộ thao tác đ c và nhi u ti n trình cùng đ c m t lúc.ọ ề ế ọ ộ

• Truy c p d li u cây Index (INDEX SCAN): duy t cây Index theo giá tr khóa c n tìm, k t qu tìm đ c cóậ ữ ệ ệ ị ầ ế ả ượ l u giá tr ROWID c a dòng d li u ch a giá tr khóaư ị ủ ữ ệ ứ ị

• Truy c p d li u Table theo Index ( TABLE ACCESS (BY INDEX ROWID)): ph ng th c truy c p này bao g mậ ữ ệ ươ ứ ậ ồ hai b c tách bi t: ướ ệ

1. Duy t cây Index đ tìm ROWID t ng ng v i giá tr khóaệ ể ươ ứ ớ ị2. Đ c dòng d li u c a Table theo ROWID tìm đ c m t cách nhanh nh tọ ữ ệ ủ ượ ộ ấ

V i cách này, ta th y đ đ c đ c m t dòng d li u c a Table thì ph i t n ít nh t hai thao tác IO; m t thaoớ ấ ể ọ ượ ộ ữ ệ ủ ả ố ấ ộ tác IO đ c trên cây Index và m t thao tác IO đ c trên Table. Theo lu t chung thì cách này thích h p khi k tọ ộ ọ ậ ợ ế qu d li u c n tìm ít h n 5% kh i l ng d li u c a Table.ả ữ ệ ầ ơ ố ượ ữ ệ ủ

Ph ng pháp JOIN ươ

Xác đ nh ph ng pháp k t h p d li u gi a hai hay nhi u Table v i nhau, ví d v ph ng pháp JOIN gi a hai Tableị ươ ế ợ ữ ệ ữ ề ớ ụ ề ươ ữ T1 và T2:

1. NESTED LOOP JOIN: v i T1 là ớ outer-table, T2 là inner-table thì t ng dòng d li u c a Table T1 s k t h p soừ ữ ệ ủ ẽ ế ợ sánh v i t t c dòng d li u c a Table T2, k t qu tr v là t t c các dòng d li u th a đi u ki n so sánh.ớ ấ ả ữ ệ ủ ế ả ả ề ấ ả ữ ệ ỏ ề ệ

2. SORT MERGE JOIN: t p dòng d li u c a hai Table đ c s p theo th t tr c khi ng d ng thu t toánậ ữ ệ ủ ượ ắ ứ ự ướ ứ ụ ậ tr n trên chúng.ộ

Th t JOINứ ự

Xác đ nh th t JOIN khi câu l nh SQL có nhi u h n hai Table k t h p v i nhau, th t JOIN h p lý giúp gi m thi uị ứ ự ệ ề ơ ế ợ ớ ứ ự ợ ả ể d li u c n k t h p v i nhau mà v n đ t đ c k t qu đúng.ữ ệ ầ ế ợ ớ ẫ ạ ượ ế ả

Sau khi tìm hi u qua các khái ni m c b n, chúng ta th quay l i tìm hi u ý nghĩa EP c a câu l nh SQL trên:ể ệ ơ ả ử ạ ể ủ ệ

1. Oracle ch n ph ng pháp JOIN là NESTED LOOP đ th c hi n phép JOIN gi a hai Table.ọ ươ ể ự ệ ữ2. Oracle ch n CUSTOMERS đóng vai trò là outer-table, COUNTRIES là inner-tableọ3. B t đ u đ c t ng dòng d li u c a CUSTOMERS r i so trùng v i t t c dòng c a COUNTRIES, đi m l u ý làắ ầ ọ ừ ữ ệ ủ ồ ớ ấ ả ủ ể ư

giá tr COUNTRIES.COUNTRY_ID này đ c l y t cây Index COUNTRY_PKị ượ ấ ừ4. K t qu tr v là t t c nh ng dòng d li u th a đi u ki n so trùngế ả ả ề ấ ả ữ ữ ệ ỏ ề ệ

Đ n đây có th các b n th c m c là t i sao Oracle l i ch n ph ng pháp Join là NESTED LOOP ? t i sao CUSTOMERSế ể ạ ắ ắ ạ ạ ọ ươ ạ l i đ c ch n làm ạ ượ ọ outer-table ?, quy t đ nh ch n này đ c th c hi n b i Trình t i u câu l nh Oracle.ế ị ọ ượ ự ệ ở ố ư ệ

Page 5: Tối ưu-cau-lệnh-oracle-sql

Trình t i u câu l nh Oracleố ư ệ

Trình t i u giúp Oracle xác đ nh đ c m t EP t t nh t cho m t câu l nh SQL. Trình t i u Oracle 9i h tr ph ngố ư ị ượ ộ ố ấ ộ ệ ố ư ỗ ợ ươ pháp t i u d a vào cú pháp l nh (Rule Based Optimizer – RBO) và ph ng pháp t i u d a vào chi phí c tính c nố ư ự ệ ươ ố ư ự ướ ầ dùng đ th c thi câu l nh (Cost Based Optimizer – CBO). M c đ nh Oracle9i dùng RBO.ể ự ệ ặ ị

RBO

RBO có t phiên b n Oracle6, d a vào c u trúc câu l nh SQL đ xác đ nh EP t t nh t. RBO s d ng m t l c đừ ả ự ấ ệ ể ị ố ấ ử ụ ộ ượ ồ phân h ng các ph ng th c truy c p d li u đ ch n ph ng th c truy c p cho EP, ph ng th c nào có s h ngạ ươ ứ ậ ữ ệ ể ọ ươ ứ ậ ươ ứ ố ạ th p s đ c u tiên ch n. L c đ phân h ng các ph ng th c truy c p d li u đ c qui đ nh nh sau:ấ ẽ ượ ư ọ ượ ồ ạ ươ ứ ậ ữ ệ ượ ị ư

Ta th y truy c p theo ROWID có s h ng th p nh t là 1; nghĩa là ph ng th c truy c p đ n d li u nhanh nh t, vàấ ậ ố ạ ấ ấ ươ ứ ậ ế ữ ệ ấ truy c p theo Index có s h ng là 4 s nhanh h n nhi u so v i truy c p theo Full-Table-Scan có s h ng cao nh t làậ ố ạ ẽ ơ ề ớ ậ ố ạ ấ 15.

Ví d sau cho th y RBO s d ng lu t phân h ng đ ch n ph ng th c truy c p d li u cho EP. Do c t CUST_ID c aụ ấ ử ụ ậ ạ ể ọ ươ ứ ậ ữ ệ ộ ủ đi u ki n WHERE có UNIQUE INDEX lên RBO ch n ph ng th c truy c p theo Index:ề ệ ọ ươ ứ ậ

SQL> DROP TABLE new_table;

Table dropped.

SQL> CREATE TABLE new_table AS

SELECT object_id, object_name, object_type

FROM all_objects

WHERE rownum <= 5000; 2 3 4

Page 6: Tối ưu-cau-lệnh-oracle-sql

Table created.

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL> SELECT * FROM new_table WHERE object_type = 'TABLE';

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'NEW_TABLE'

SQL> SET AUTOTRACE OFF

SQL> CREATE INDEX idx_object_type ON new_table(object_type);

Index created.

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL> SELECT * FROM new_table WHERE object_type = 'TABLE';

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'NEW_TABLE'

2 1 INDEX (RANGE SCAN) OF 'IDX_OBJECT_TYPE' (NON-UNIQUE)

CBO

CBO có t phiên b n Oracle7, CBO d a vào “thông tin t ng h p” đ c đ c tính chi phí c a EP, EP t t nh t là EPừ ả ự ổ ợ ượ ể ướ ủ ố ấ có chi phí c tính nh nh t. Oracle9i ch dùng CBO đ t i u n u đ i t ng tham chi u đ n có thông tin mô t .ướ ỏ ấ ỉ ể ố ư ế ố ượ ế ế ả

“Thông tin t ng h p” trong ng c nh này bao g m:ổ ợ ữ ả ồ

1. Thông tin v h đi u hành máy ch Oracle: s CPU, t c đ đ c ghi đĩa c ng, kích th c kh i d li u, cề ệ ề ủ ố ố ộ ọ ứ ướ ố ữ ệ ơ ch qu n lý đĩa …ế ả

2. Thông tin mô t các đ i t ng d li u: s dòng, c t và kh i d li u c a Table, kích th c dòng, chi u caoả ố ượ ữ ệ ố ộ ố ữ ệ ủ ướ ề và s nút lá c a cây Index …ố ủ

3. Thông tin v các thông s liên quan: optimizer_mode, db_file_multiblock_read_count,ề ố parallel_automatic_tuning …

Page 7: Tối ưu-cau-lệnh-oracle-sql

N u cung c p đ y đ và chính xác các thông tin trên, trình t i u CBO có th xác đ nh đ c m t EP t t nh t.ế ấ ầ ủ ố ư ể ị ượ ộ ố ấ

Ti p theo ví d trong ph n RBO, chúng ta dùng l nh ANALYZE TABLE đ thu th p thông tin c a NEW_TABLE cho trìnhế ụ ầ ệ ể ậ ủ t i u: ố ư

SQL> SET AUTOTRACE OFF

SQL> @li NEW_TABLE

indexes on table NEW_TABLE%:

TABLE_NAME INDEX_TYPE INDEX_NAME

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

NEW_TABLE NONUNIQUE IDX_OBJECT_TYPE

SQL> ANALYZE TABLE new_table COMPUTE STATISTICS;

Table analyzed.

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL>SELECT * FROM new_table WHERE object_type = 'TABLE';

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=2500 Bytes=107500)

1 0 TABLE ACCESS (FULL) OF 'NEW_TABLE' (Cost=5 Card=2500 Bytes=107500)

Ta th y k t qu c a EP có m t s đi m khác bi t so v i th i đi m tr c khi thu th p thông tin:ấ ế ả ủ ộ ố ể ệ ớ ờ ể ướ ậ

1. Có thêm thông tin v chi phí th c hi n c a m i b c l nh: (Cost=5 Card=2500 Bytes=107500), đi u nàyề ự ệ ủ ỗ ướ ệ ề ch ng t Oracle hi n đang dùng trình t i u CBOứ ỏ ệ ố ư

2. CBO ch n ph ng th c truy c p TABLE ACCESS (FULL) m c dù có t n t i Index trên c t object_type.ọ ươ ứ ậ ặ ồ ạ ộ

Page 8: Tối ưu-cau-lệnh-oracle-sql

Ph l c ụ ụ

Gi i nghĩa tả ừ

Bind-variable: k thu t vi t mã không gán giá tr c đ nh, k thu t này giúp tăng tính s n sàng, hi u năng và b oỹ ậ ế ị ố ị ỹ ậ ẵ ệ ả m t cho h th ng Oracle. Ví d : ậ ệ ố ụ

Mã không dùng Bind-Variable

BEGIN

UPDATE employees SET SALARY=SALARY + 100 WHERE employee_id = 100;

END;

Mã dùng Bind-Variable

DECLARE

bind_var NUMBER := 100;

BEGIN

UPDATE employees SET SALARY=SALARY + 100 WHERE employee_id = bind_var;

END;

Outer-table: t ng dòng d li u c a Table này s đ i sánh v i t t c dòng c a inner-table, còn g i là driving-table,ừ ữ ệ ủ ẽ ố ớ ấ ả ủ ọ đ c đ c p đ n trong ph ng pháp NESTED LOOP JOIN, th ng đi chung v i thu t ng inner-tableượ ề ậ ế ươ ườ ớ ậ ữ

Inner-table: t t c dòng d li u c a Table này s đ c đ i sánh v i t ng dòng c a outer-table. ấ ả ữ ệ ủ ẽ ượ ố ớ ừ ủ

Page 9: Tối ưu-cau-lệnh-oracle-sql

Mã l nhệ

M t s File mã l nh ti n ích s d ng trong bài vi t: ộ ố ệ ệ ử ụ ế

Tên mã l nhệ Mô t ch c năngả ứ

li.sql

Li t kê t t c Index c a b ng nh p vàoệ ấ ả ủ ả ậ

select ui.table_name

, decode(ui.index_type

,'NORMAL', ui.uniqueness

,ui.index_type) as index_type

, ui.index_name

from user_indexes ui

where ui.table_name like upper('&1.%')

order by ui.table_name, ui.uniqueness desc

L ch s thay đ iị ử ổ

1. 10/02/2009 - Gi i thi u bài vi tớ ệ ế2. 20/02/2009 - B sung ph n "Công c t i u câu l nh: SQL*Plus AUTOTRACEổ ầ ụ ố ư ệ

Tham kh oả

1. Cách s d ng "Bind Variable" khi l p trình Java v i Oracleử ụ ậ ớ 2. Tài li u chu n c a Oracle Database 9iệ ẩ ủ 3. Tài li u khóa h c Oracle Database 9i: SQL Tuningệ ọ

M i các b n đ c ph n ti p theo c a ch đ này: ờ ạ ọ ầ ế ủ ủ ề

Ph n 2 – T i u câu l nh SQL có Table và có m t đi u ki nầ ố ư ệ ộ ề ệ

Page 10: Tối ưu-cau-lệnh-oracle-sql

Ph n 2: T i u câu l nh SQL có m t Tableầ ố ư ệ ộ và có m t đi u ki nộ ề ệTi p theo ế Ph n 1: n n t ng c b n t i u câu l nh Oracle SQLầ ề ả ơ ả ố ư ệ ; gi i thi u các ki n th c c b n c n thi t đ t i uớ ệ ế ứ ơ ả ầ ế ể ố ư câu l nh SQL, chúng ta b t đ u đi vào tìm hi u k thu t t i u câu l nh c b n nh t, đó là t i u d a vào Index, cệ ắ ầ ể ỹ ậ ố ư ệ ơ ả ấ ố ư ự ụ th là B*tree-Index, lo i Index th ng đ c dùng nh t. ể ạ ườ ượ ấ

Chúng ta cũng c n l u ý là Index ch giúp tăng t c đ truy v n trong m t s tr ng h p c th , không ph i b t kìầ ư ỉ ố ộ ấ ộ ố ườ ợ ụ ể ả ấ tr ng h p nào s d ng Index cũng giúp tăng t c đ . Trong th c t , ta có th xem ph n m c l c c a m t cu nườ ợ ử ụ ố ộ ự ế ể ầ ụ ụ ủ ộ ố sách gi ng nh m t c u trúc Index; t m c l c cu n sách, b n suy ra đ c s th t trang sách ch a n i dung b nố ư ộ ấ ừ ụ ụ ố ạ ượ ố ứ ự ứ ộ ạ c n tìm. N u sách vài trăm trang b n có th d a vào m c l c đ tìm đ c n i dung mong mu n m t cách nhanhầ ế ạ ể ự ụ ụ ể ượ ộ ố ộ chóng, nh ng n u sách ch vài trang thì tìm theo cách l t t ng trang thì l i nhanh h n. Cách tìm theo m c l c gi ngư ế ỉ ậ ừ ạ ơ ụ ụ ố nh ph ng th c truy c p TABLE ACCESS (BY INDEX ROWID), cách tìm l t t ng trang sách gi ng nh ph ng th cư ươ ứ ậ ậ ừ ố ư ươ ứ truy c p TABLE ACCESS (FULL). ậ

Ph n hai này s t p trung ch y u vào k thu t t i u câu l nh s d ng Index, xem xét tr ng h p nào Oracle sầ ẽ ậ ủ ế ỹ ậ ố ư ệ ử ụ ườ ợ ẽ dùng Index trong câu l nh và ng c l i. Các ví d minh h a trong bài s dùng Table tên CUSTOMERS c a tài kho nệ ượ ạ ụ ọ ẽ ủ ả SH, c u trúc CUSTOMERS nh sau:ấ ư

[oracle@localhost LABS]$ sid

ORACLE_SID=ora9i

[oracle@localhost LABS]$

[oracle@localhost LABS]$ alias sh

alias sh='sqlplus "sh/sh"'

[oracle@localhost LABS]$ sh

SQL*Plus: Release 9.2.0.4.0 - Production on Mon Feb 16 08:56:20 2009

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:

Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

With the Partitioning and Oracle Data Mining options

JServer Release 9.2.0.4.0 - Production

Page 11: Tối ưu-cau-lệnh-oracle-sql

SQL> DESC customers

Name Null? Type

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

CUST_ID NOT NULL NUMBER

CUST_FIRST_NAME NOT NULL VARCHAR2(20)

CUST_LAST_NAME NOT NULL VARCHAR2(40)

CUST_GENDER CHAR(1)

CUST_YEAR_OF_BIRTH NUMBER(4)

CUST_MARITAL_STATUS VARCHAR2(20)

CUST_STREET_ADDRESS NOT NULL VARCHAR2(40)

CUST_POSTAL_CODE NOT NULL VARCHAR2(10)

CUST_CITY NOT NULL VARCHAR2(30)

CUST_STATE_PROVINCE VARCHAR2(40)

COUNTRY_ID NOT NULL CHAR(2)

CUST_MAIN_PHONE_NUMBER VARCHAR2(25)

CUST_INCOME_LEVEL VARCHAR2(30)

CUST_CREDIT_LIMIT NUMBER

CUST_EMAIL VARCHAR2(30)

CUST_TOTAL VARCHAR2(14)

SQL>

Các tr ng h p ng d ng Index khi t i u câu l nh SQL ườ ợ ứ ụ ố ư ệ

Oracle không dùng Index cho đi u ki n so sánh có toán t ề ệ ử < >, != và NOT IN

Page 12: Tối ưu-cau-lệnh-oracle-sql

Th ng chúng ta nghĩ n u c t d li u trong m nh đ đi u ki n có Index, thì câu l nh SQL s s d ng Index đ truyườ ế ộ ữ ệ ệ ề ề ệ ệ ẽ ử ụ ể v n d li u cho nhanh, tuy nhiên có nhi u tr ng h p dù có Index nh ng Index v n không đ c. Tr ng h p đ uấ ữ ệ ề ườ ợ ư ẫ ượ ườ ợ ầ tiên chúng ta xét đ n là đ i v i các toán t ế ố ớ ử <>, != và NOT IN.

Tr c tiên, ta ki m tra Table tên CUSTOMERS hi n đang có nh ng Index nào:ướ ể ệ ữ

SQL> @li CUSTOMERS

indexes on table CUSTOMERS%:

TABLE_NAME INDEX_TYPE INDEX_NAME

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

CUSTOMERS UNIQUE CUSTOMERS_PK

NONUNIQUE CUST_CREDIT_LIMIT_IDX

CUST_EMAIL_IDX

CUST_LAST_NAME_IDX

Dùng mã l nh ệ dai.sql xóa các nonprimary-key, khi đó CUSTOMERS ch còn ỉ primary-key tên CUSTOMERS_PK trên c t d li u CUST_ID:ộ ữ ệ

SQL> @dai

on which table: CUSTOMERS

DROP INDEX CUSTOMERS_PK

*

ERROR at line 1:

ORA-02429: cannot drop index used for enforcement of unique/primary key

SQL> @li CUSTOMERS

indexes on table CUSTOMERS%:

Page 13: Tối ưu-cau-lệnh-oracle-sql

TABLE_NAME INDEX_TYPE INDEX_NAME

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

CUSTOMERS UNIQUE CUSTOMERS_PK

Xem cách trình t i u Oracle x lý b n câu l nh sau:ố ư ử ố ệ

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL> SELECT cust_first_name, cust_last_name

FROM customers

WHERE cust_id = 1030

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS'

2 1 INDEX (UNIQUE SCAN) OF 'CUSTOMERS_PK' (UNIQUE)

SQL> SELECT cust_first_name, cust_last_name

FROM customers

WHERE cust_id < 20000

/

Execution Plan

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

Page 14: Tối ưu-cau-lệnh-oracle-sql

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS'

2 1 INDEX (RANGE SCAN) OF 'CUSTOMERS_PK' (UNIQUE)

SQL> SELECT cust_first_name, cust_last_name

FROM customers

WHERE cust_id between 70000 and 80000

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS'

2 1 INDEX (RANGE SCAN) OF 'CUSTOMERS_PK' (UNIQUE)

SQL> SELECT cust_first_name, cust_last_name

FROM customers

WHERE cust_id <> 1030

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

Page 15: Tối ưu-cau-lệnh-oracle-sql

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL>

Nhìn vào k t qu các câu l nh, ta th y trình t i u Oracle đang đ c ch đ nh giá tr là Optimizer=CHOOSE, nghĩa làế ả ệ ấ ố ư ượ ỉ ị ị s ch n CBO n u CUSTOMERS có thông tin mô t và ch n RBO n u không có. M c đ nh CUSTOMERS không có thôngẽ ọ ế ả ọ ế ặ ị tin mô t , vì v y trong tr ng h p này trình t i u s dùng ph ng pháp RBO đ xác đ nh EP cho các câu l nh. ả ậ ườ ợ ố ư ẽ ươ ể ị ệ

Nh tìm hi u trong ph n tr c, RBO s d ng l c đ lu t phân h ng đ ch n EP t t nh t, u tiên ch n ph ngư ể ầ ướ ử ụ ượ ồ ậ ạ ể ọ ố ấ ư ọ ươ th c truy c p d li u theo Index h n là ph ng th c duy t t ng dòng d li u c a Table. Nh ng theo ví d trên, taứ ậ ữ ệ ơ ươ ứ ệ ừ ữ ệ ủ ư ụ th y RBO ch dùng Index cho 3 câu l nh đ u tiên, không dùng Index cho câu l nh cu i cùng. Đ ý thì ta th y ba câuấ ỉ ệ ầ ệ ố ể ấ l nh đ u s d ng toán t so sánh ệ ầ ử ụ ử =, < và BETWEEN AND, các toán t này đ u có khuynh h ng gi i h n t p dử ề ướ ớ ạ ậ ữ li u tr v , còn câu l nh th t thì s d ng toán t ệ ả ề ệ ứ ư ử ụ ử <>, toán t này luôn tr v t p k t qu l n. Nh v y, Oracleử ả ề ậ ế ả ớ ư ậ RBO ng x nh v y là h p lý, dùng Index cho câu l nh s d ng toán t so sánh có khuynh h ng tr v ít d li uứ ử ư ậ ợ ệ ử ụ ử ướ ả ề ữ ệ và không dùng Index cho tr ng h p câu l nh có toán t so sánh tr v nhi u d li u.ườ ợ ệ ử ả ề ề ữ ệ

RBO s ng x t ng t nh ẽ ứ ử ươ ự ư <> cho các toán t ử != và NOT IN.

Oracle không dùng Index cho c t d li u k t h p v i b t kì thành ph n khácộ ữ ệ ế ợ ớ ấ ầ

Dù c t d li u có Index, nh ng n u ta k t h p nó v i b t kì thành ph n nào khác, ch ng h n nh m t giá tr , m tộ ữ ệ ư ế ế ợ ớ ấ ầ ẳ ạ ư ộ ị ộ bi u th c thì Index trên c t d li u đó s không đ c trình t i u Oracle ng dùng. Xem xét các ví d d i đây:ể ứ ộ ữ ệ ẽ ượ ố ư ứ ụ ướ

SQL> SELECT *

2 FROM customers

3 WHERE cust_id + 1 = 100;

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL> SELECT *

2 FROM customers

3 WHERE TO_NUMBER(cust_id) = 100;

Page 16: Tối ưu-cau-lệnh-oracle-sql

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL> SELECT *

2 FROM customers

3 WHERE cust_id + null = 100;

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL> SELECT *

2 FROM customers

3 WHERE cust_id = 100;

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS'

Page 17: Tối ưu-cau-lệnh-oracle-sql

2 1 INDEX (UNIQUE SCAN) OF 'CUSTOMERS_PK' (UNIQUE)

SQL>

Ta th y ba tr ng h p đ u tiên, dù c t d li u k t h p v i giá tr NULL , giá tr r ng, cũng khi n Oracle RBO khôngấ ườ ợ ầ ộ ữ ệ ế ợ ớ ị ị ỗ ế ng d ng Index cho câu l nh. Đ i v i tr ng h p TO_NUMBER(cust_id) thì do hàm TO_NUMBER k t bu c v i c tứ ụ ệ ố ớ ườ ợ ế ộ ớ ộ

CUST_ID nên làm m t tác d ng c a Index, tuy nhiên chúng ta có th s d ng k thu t ấ ụ ủ ể ử ụ ỹ ậ function-based Index; t oạ Index tr c ti p trên hàm k t bu c vào c t d li u, ự ế ế ộ ộ ữ ệ đ th c hi n ph ng th c truy c p d li u theo Index mà khôngể ự ệ ươ ứ ậ ữ ệ c n b hàm TO_NUMBER().ầ ỏ

SQL> CREATE INDEX cust_id_tonumber_idx ON customers(to_number(cust_id));

Index created.

SQL> @li

indexes on table CUSTOMERS%:

TABLE_NAME INDEX_TYPE INDEX_NAME

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

CUSTOMERS UNIQUE CUSTOMERS_PK

NONUNIQUE CUST_CREDIT_LIMIT_IDX

FUNCTION-B CUST_ID_TONUMBER_IDX

ASED NORMA

L

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

Page 18: Tối ưu-cau-lệnh-oracle-sql

SQL> SELECT *

2 FROM customers

3 WHERE to_number(cust_id) = 100;

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL> ANALYZE TABLE customers COMPUTE STATISTICS;

Table analyzed.

SQL> SELECT *

2 FROM customers

3 WHERE to_number(cust_id) = 100;

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=137)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS' (Cost=2 Card=1 Bytes=137)

2 1 INDEX (RANGE SCAN) OF 'CUST_ID_TONUMBER_IDX' (NON-UNIQUE) (Cost=1 Card=1)

Page 19: Tối ưu-cau-lệnh-oracle-sql

SQL>

Nh ta th y, ch trình t i u CBO m i hi u k thu t Function-based Index, RBO không hi u. Vì v y, đ trình t i uư ấ ỉ ố ư ớ ể ỹ ậ ể ậ ể ố ư Oracle t đ ng dùng CBO thì chúng ta c n thu th p thông tin mô t cho CUSTOMERS.ự ộ ầ ậ ả

L u ý thêm v cách thu th p thông tin mô t cho Table, chúng ta s d ng cú pháp l nh ANALYZE TABLE vì l nh nàyư ề ậ ả ử ụ ệ ệ đ n gi n, d hi u và cú pháp trong sáng, đáp ng đ cho các minh h a c a chúng ta. Khi ng d ng thu th p thôngơ ả ễ ể ứ ủ ọ ủ ứ ụ ậ tin cho h th ng Oracle th c t , các b n nên dùng gói l nhệ ố ự ế ạ ệ DBMS_STATS thì hi u qu h n.ệ ả ơ

Oracle Index và toán t LIKEử

Đ minh h a cho ý này, chúng ta s t o thêm m t Index trên c t d li u CUST_LAST_NAME theo mã l nh ể ọ ẽ ạ ộ ộ ữ ệ ệ ci.sql:

SQL> @ci

on which table : CUSTOMERS

on which column(s): cust_last_name

Creating index on: CUSTOMERS cust_last_name

Enter value for index_name: cust_last_name_idx

SQL> @li CUSTOMERS

indexes on table CUSTOMERS%:

TABLE_NAME INDEX_TYPE INDEX_NAME

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

CUSTOMERS UNIQUE CUSTOMERS_PK

NONUNIQUE CUST_CREDIT_LIMIT_IDX

FUNCTION-B CUST_ID_TONUMBER_IDX

ASED NORMA

L

Page 20: Tối ưu-cau-lệnh-oracle-sql

NONUNIQUE CUST_LAST_NAME_IDX

Ti p theo, chúng ta xét ví d sau:ế ụ

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL> SELECT cust_id

2 FROM customers

3 WHERE cust_last_name LIKE 'S%'

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'CUSTOMERS'

2 1 INDEX (RANGE SCAN) OF 'CUST_LAST_NAME_IDX' (NON-UNIQUE)

SQL> SELECT cust_last_name

2 FROM customers

3 WHERE cust_last_name LIKE '%S%’

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

Page 21: Tối ưu-cau-lệnh-oracle-sql

SQL> SELECT cust_id

2 FROM customers

3 WHERE cust_last_name LIKE '%S'

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL>

Nh v y, trình t i u Oracle RBO ch ng d ng Index cho toán t LIKE n u giá tr so sánh không có kí t đ c bi t ư ậ ố ư ỉ ứ ụ ử ế ị ự ặ ệ % đ u. ở ầ

Chúng ta xét ti p ví d sau:ế ụ

SQL> SELECT cust_last_name

2 FROM customers

3 WHERE cust_last_name like 'S%'

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 INDEX (RANGE SCAN) OF 'CUST_LAST_NAME_IDX' (NON-UNIQUE)

SQL>

Page 22: Tối ưu-cau-lệnh-oracle-sql

Các b n th y đi m khác bi t đây ch ? EP không có b c l nh TABLE ACCESS (BY INDEX ROWID) nh bìnhạ ấ ể ệ ở ứ ướ ệ ư th ng, mà ch có INDEX (RANGE SCAN). ườ ỉ

Nguyên nhân do c t d li u k t qu tr v ch có CUST_LAST_NAME, mà d li u này chính là giá tr khóa c a Indexộ ữ ệ ế ả ả ề ỉ ữ ệ ị ủ tên CUST_LAST_NAME_IDX, vì v y Oracle ch c n duy t cây Index là có th l y đ c k t qu mong mu n, không c nậ ỉ ầ ệ ể ấ ượ ế ả ố ầ t n thêm chi phí duy t Table nh bình th ng.ố ệ ư ườ

Ti p t c v i ví d sau:ế ụ ớ ụ

SQL> SELECT cust_last_name

2 FROM customers

3 WHERE cust_id LIKE '7%'

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL>

Các b n có đoán ra đ c lý do t i sao trình t i u Oracle RBO không ng dùng Index trên c t d li u CUST_ID ? Doạ ượ ạ ố ư ứ ộ ữ ệ CUST_ID là c t d li u ki u s , nh ng câu l nh l i so sánh v i m t giá tr chu i ‘7%’, nên trong tr ng h p nàyộ ữ ệ ể ố ư ệ ạ ớ ộ ị ỗ ườ ợ Oracle t đ ng ng m đ nh chuy n đ i ki u cho m nh đ đi u ki n thành nh sau:ự ộ ầ ị ể ổ ể ệ ề ề ệ ư

SQL> SELECT cust_last_name

2 FROM customers

3 WHERE TO_CHAR(cust_id) LIKE '7%'

Do c t d li u CUST_ID b k t bu c v i hàm TO_CHAR() khi so sánh, nên b m t tác d ng Index.ộ ữ ệ ị ế ộ ớ ị ấ ụ

Tóm t t nh ng ý chúng ta đã tìm hi u đ c trong ph n này:ắ ữ ể ượ ầ

1. Oracle ch ng d ng Index cho toán t LIKE khi giá tr so sánh không có kí t ỉ ứ ụ ử ị ự % đ u ở ầ2. N u k t qu d li u c a câu l nh có th tìm th y đ trong Index, thì Oracle ch c n duy t cây Index đ l yế ế ả ữ ệ ủ ệ ể ấ ủ ỉ ầ ệ ể ấ

k t qu tr v , mà không c n duy t trên Table.ế ả ả ề ầ ệ3. N u c t d li u trong m nh đ đi u ki n so sánh v i m t giá tr khác ki u, Oracle t đ ng chuy n đ i ki uế ộ ữ ệ ệ ề ể ệ ớ ộ ị ể ự ộ ể ổ ể

ng m đ nh cho c t d li u đó, đi u này khi n Index không đ c ng d ng.ầ ị ộ ữ ệ ề ế ượ ứ ụ

Page 23: Tối ưu-cau-lệnh-oracle-sql

Oracle Index và giá tr NULLị

Theo ki n trúc c s d li u Oracle, c u trúc cây Index ,B*tree-Index, không l u thông tin v dòng d li u c a Tableế ơ ở ữ ệ ấ ư ề ữ ệ ủ có giá tr khóa là NULL. V y theo b n, Oracle s ng x th nào khi so sánh đi u ki n trên c t d li u có giá trị ậ ạ ẽ ứ ử ế ề ệ ộ ữ ệ ị NULL ? chúng ta s tìm hi u ý này ngay trong ph n d i đây.ẽ ể ầ ướ

Đ chu n b cho ph n này, chúng ta c p nh t m t s giá tr c a c t d li u CUST_EMAIL v NULL và t o Index tênể ẩ ị ầ ậ ậ ộ ố ị ủ ộ ữ ệ ề ạ CUST_EMAIL_IDX trên c t này.ộ

SQL> SET AUTOTRACE OFF

SQL> UPDATE customers

2 SET cust_email = null

3 WHERE rownum < 101

/

100 rows updated.

SQL> COMMIT;

Commit complete.

SQL> @ci

on which table : CUSTOMERS

on which column(s): CUST_EMAIL

Creating index on: CUSTOMERS CUST_EMAIL

Enter value for index_name: CUST_EMAIL_IDX

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

Page 24: Tối ưu-cau-lệnh-oracle-sql

SQL> SELECT cust_email

2 FROM customers

3 WHERE cust_email IS NULL

/

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

SQL>

Theo ví d trên, Oracle đã không dùng Index dù c t CUST_EMAIL có Index. Gi i thích cho cách ng x này là doụ ộ ả ứ ử B*tree-Index không l u thông tin v dòng d li u ch a giá tr khóa là NULL, vì v y Oracle ph i th c hi n quét t ngư ề ữ ệ ứ ị ậ ả ự ệ ừ dòng d li u c a Table đ tìm đ c các CUST_EMAIL có giá tr NULL.ữ ệ ủ ể ượ ị

V y các b n th xem ti p ví d sau, t i sao Oracle v n không dùng Index ?ậ ạ ử ế ụ ạ ẫ

SQL> SET AUTOTRACE TRACEONLY EXPLAIN

SQL> SELECT cust_id

2 FROM customers

3* WHERE cust_email IS NOT NULL

SQL> /

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'CUSTOMERS'

Page 25: Tối ưu-cau-lệnh-oracle-sql

SQL>

N u Oracle B*tree-Index không l u giá tr NULL, v y khi tìm giá tr khác NULL thì theo suy lu n bình th ng Oracleế ư ị ậ ị ậ ườ ph i dùng Index trong tr ng h p này ? Không nh v y, Oracle “nghĩ” r ng đi u ki n IS NOT NULL s tr v t p k tả ườ ợ ư ậ ằ ề ệ ẽ ả ề ậ ế qu l n, n u dùng Index s không hi u qu , nên Oracle ch n ph ng th c truy c p d li u TABLE ACCESS (FULL) sả ớ ế ẽ ệ ả ọ ươ ứ ậ ữ ệ ẽ hi u qu h n.ệ ả ơ

Ph l c ụ ụ

Mã l nhệ

M t s File mã l nh ti n ích s d ng trong bài vi t: ộ ố ệ ệ ử ụ ế

Tên mã l nhệ Mô t ch c năngả ứ

li.sql

Li t kê t t c Index c a b ng nh p vàoệ ấ ả ủ ả ậ

select ui.table_name, decode(ui.index_type ,'NORMAL', ui.uniqueness ,ui.index_type) as index_type, ui.index_namefrom user_indexes uiwhere ui.table_name like upper('&1.%')order by ui.table_name, ui.uniqueness desc

dai.sql

Xóa h t t t c non-primary key Index trên m t c t d li u nh p vào c a m t Tableế ấ ả ộ ộ ữ ệ ậ ủ ộ

accept TABLE_NAME prompt " on which table: "set termout offstore set saved_settings replaceset heading off verify off autotrace off feedback off

spool doit.sql

select 'DROP INDEX '||ui.index_name||';'from user_indexes uiwhere table_name like upper('&TABLE_NAME.%')/

spool offset termout on@doit@saved_settingsundef TABLE_NAMEset termout on

ci.sqlT o m i m t Non-Unique Index trên m t c t d li u nh p vào c a m t Tableạ ớ ộ ộ ộ ữ ệ ậ ủ ộ

accept TABLE_NAME prompt " on which table : "

Page 26: Tối ưu-cau-lệnh-oracle-sql

|accept COLUMN_NAME prompt " on which column(s): "

set termout offstore set saved_settings replaceset heading off feedback off autotrace offset verify off termout on

select 'Creating index on: ', '&&TABLE_NAME', '&&COLUMN_NAME'FROM DUAL/

create index &INDEX_NAME on &TABLE_NAME(&COLUMN_NAME)/

@saved_settingsset termout onundef INDEX_NAMEundef TABLE_NAMEundef COLUMN_NAME