?
一、執(zhí)行順序及優(yōu)化細(xì)則
1.表名順序優(yōu)化
(1) 基礎(chǔ)表放下面,當(dāng)兩表進(jìn)行關(guān)聯(lián)時(shí)數(shù)據(jù)量少的表的表名放右邊
表或視圖:
Student_info?? (30000條數(shù)據(jù))
Description_info (30條數(shù)據(jù))?
select *
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'?????
與???
select *
? from student_info???? si--學(xué)生信息表
????? ,description_info di
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'??
以student_info作為基礎(chǔ)表,你會(huì)發(fā)現(xiàn)運(yùn)行的速度會(huì)有很大的差距。
??
??
(2) 當(dāng)出現(xiàn)多個(gè)表時(shí),關(guān)聯(lián)表被稱之為交叉表,交叉表作為基礎(chǔ)表
select *
? from description_info di
??? ,description_info di2
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and si.school_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'SCHOOL_ID'
與
select *
? from student_info???? si--學(xué)生信息表
????? ,description_info di
????? ,description_info di2
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and si.school_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'SCHOOL_ID'
以student_info作為基礎(chǔ)表,你會(huì)發(fā)現(xiàn)運(yùn)行的速度會(huì)有很大的差距,
當(dāng)基礎(chǔ)表放在后面,這樣的執(zhí)行速度會(huì)明顯快很多。
2.where執(zhí)行順序
where執(zhí)行會(huì)從至下往上執(zhí)行
select *
from student_info si --學(xué)生信息表
where si.school_id=10 --學(xué)院ID
and? si.system_id=100--系ID
擺放where子句時(shí),把能過(guò)濾大量數(shù)據(jù)的條件放在最下邊
3. is null 和is not null
當(dāng)要過(guò)濾列為空數(shù)據(jù)或不為空的數(shù)據(jù)時(shí)使用
select *
from student_info si --學(xué)生信息表
where si.school_id is null(當(dāng)前列中的null為少數(shù)時(shí)用is not null,否則is null)
4.使用表別名
當(dāng)查詢時(shí)出現(xiàn)多個(gè)表時(shí),查詢時(shí)加上別名,
避免出現(xiàn)減少解析的時(shí)間字段歧義引起的語(yǔ)法錯(cuò)誤。
5. where執(zhí)行速度比having快
盡可能的使用where代替having
select? from student_info si
group by si.student_id
having si.system_id!=100
? and si.school_id!=10
(select? from student_info si
wehre si.system_id!=100
and si.school_id!=10
group by si.student_id)?
?
6.? * 號(hào)引起的執(zhí)行效率
盡量減少使用select * 來(lái)進(jìn)行查詢,當(dāng)你查詢使用*,
數(shù)據(jù)庫(kù)會(huì)進(jìn)行解析并將*轉(zhuǎn)換為全部列。
二、替代優(yōu)化
1、用>=替代>
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id>=10
? 與
? select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id>9
? 執(zhí)行時(shí)>=會(huì)比>執(zhí)行得要快
?
2、用UNION替換OR (適用于索引列)
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=10
? union
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=2?
?? 上面語(yǔ)句可有效避免全表查詢
?? select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=10
? or ui.student_id=2
? 如果堅(jiān)持要用OR, 可以把返回記錄最少的索引列寫在最前面
???
3、用in 代替or
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=10
? or ui.student_id=20
? or ui.student_id=30
? 改成
? select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id in (10,20,30)
? 執(zhí)行會(huì)更有效率
???
4、 Union All 與Union
Union All重復(fù)輸出兩個(gè)結(jié)果集合中相同記錄
如果兩個(gè)并集中數(shù)據(jù)都不一樣.那么使用Union All 與Union是沒有區(qū)別的,
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=10
? union All
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=2?
? 與
? select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=10
? union
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id=2?
但Union All會(huì)比Union要執(zhí)行得快
5、分離表和索引
總是將你的表和索引建立在另外的表空間內(nèi)
決不要將這些對(duì)象存放到SYSTEM表空間里
三、一些優(yōu)化技巧
1、計(jì)算表的記錄數(shù)時(shí)
select count(si.student_id)
from Student_info si(student_id為索引)
與
select count(*) from Student_info si
執(zhí)行時(shí).上面的語(yǔ)句明顯會(huì)比下面沒有用索引統(tǒng)計(jì)的語(yǔ)句要快
2.使用函數(shù)提高SQL執(zhí)行速度
當(dāng)出現(xiàn)復(fù)雜的查詢sql語(yǔ)名,可以考慮使用函數(shù)來(lái)提高速度
查詢學(xué)生信息并查詢學(xué)生(李明)個(gè)人信息與的數(shù)學(xué)成績(jī)排名
如
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.description = '李明'
??
而且我們將上面order_num排名寫成一個(gè)fuction時(shí)
create or replace package body order_num_pkg is
function order_num(p_student_id number) return_number is
? v_return_number number;
begin
? select res.order_num --排名
??? into v_return_number
??? from result res
?? where res.student_id = di.student_id
?? order by result_math;
? return v_return_number;
exception
? when others then
??? null;
??? return null;
end;
end order_num_pkg;
執(zhí)行
select di.description student_name
????? ,order_num_pkg.order_num(di.student_id) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.description = '李明'
執(zhí)行查詢時(shí)的速度也會(huì)有所提高????
?
3.減少訪問(wèn)數(shù)據(jù)庫(kù)的次數(shù)
執(zhí)行次數(shù)的減少(當(dāng)要查詢出student_id=100的學(xué)生和student_id=20的學(xué)生信息時(shí))
select address_id
from student_info si --學(xué)生信息表
where si.student_id=100
與
select address_id
from student_info si --學(xué)生信息表
where si.student_id=20
都進(jìn)行查詢.這樣的效率是很低的
而進(jìn)行
(
select si.address_id,si2.address_id
from student_info si --學(xué)生信息表
,student_info si2
where si.student_id=100
and si2.student_id=20
與
select decode(si.student_id,100,address_id)
?? ,decode(si.student_id,20,address_id)
from student_info si
)
執(zhí)行速度是提高了,但可讀性反而差了..
所以這種寫法個(gè)人并不太推薦
4、用Exists(Not Exists)代替In(Not In)
?? 在執(zhí)行當(dāng)中使用Exists或者Not Exists可以高效的進(jìn)行查詢
5、Exists取代Distinct取唯一值的
?? 取出關(guān)聯(lián)表部門對(duì)員工時(shí),這時(shí)取出員工部門時(shí),出現(xiàn)多條..
select distinct di.dept_name
? from departments_info di --部門表
????? ,user_info??????? ui --員工信息表
where ui.dept_no = di.dept_no
?? 可以修改成
? select di.dept_name
??? from departments_info di --部門表
?? where? exists (select 'X'
??????????? from user_info ui --員工信息表
?????????? where di.dept_no = ui.dept_no)
6、用表連接代替Exists
?? 通過(guò)表的關(guān)聯(lián)來(lái)代替exists會(huì)使執(zhí)行更有效率
select ui.user_name
? from user_info ui--員工信息表
where exists (select 'x '
????????? from departments_info di--部門表
???????? where di.dept_no = ui.dept_no
?????????? and ui.dept_cat = 'IT');
執(zhí)行是比較快,但還可以使用表的連接取得更快的查詢效率
?? select ui.user_name
??? from departments_info di
??????? ,user_info??????? ui --員工信息表
?? where ui.dept_no = di.dept_no
???? and ui.department_type_code = 'IT'
代碼是經(jīng)測(cè)試并進(jìn)行優(yōu)化所寫,
以上只例子,具體使用還是要針對(duì)各個(gè)不同的具體的業(yè)務(wù)使用用Exists(Not Exists)代替In(Not In)
四、索引篇
1、運(yùn)算導(dǎo)致的索引失效
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and si.student_id+0=100/*student_id索引將失效*/
??
2、類型轉(zhuǎn)換導(dǎo)致的索引失效
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.student_id='100'
?
student_id為number類型的索引,當(dāng)執(zhí)行下列語(yǔ)句,
oracle會(huì)自動(dòng)轉(zhuǎn)換成
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.student_id=to_number('100')
所幸,只是解析并轉(zhuǎn)換類型,并沒有導(dǎo)到失效,
但要是寫成下面,將會(huì)使用其失效
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and to_char(di.student_id)='100'
??
3、在索引列上進(jìn)行計(jì)算引起的問(wèn)題
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.student_id-2=10
在索引列中進(jìn)行運(yùn)算,將會(huì)不使用索引而使用全表掃描
而將
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.student_id=10+2
將會(huì)得到高效的運(yùn)行速度
4、 Is not null引起的問(wèn)題(student_id為索引)
不要把存在空值的列做為索引,否則無(wú)法使用索引
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id is not null--索引失效
?
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id>=-1--索引有效
5、Order by導(dǎo)致索引失效(student_id為索引)
select ui.user_name
? from user_info ui--員工信息表
? group by ui.student_id??
而使用
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id>=-1
? 將使其有效,
? 在order by中只存在兩種條件下可以使用索引
? (ORDER BY中所有的列必須包含在相同的索引中并保持在索引中的排列順序
ORDER BY中所有的列必須定義為非空. )
?
6、自動(dòng)選擇索引
?
如果表中有兩個(gè)以上(包括兩個(gè))索引,其中有一個(gè)唯一性索引,而其他是非唯一性.
在這種情況下,ORACLE將使用唯一性索引而完全忽略非唯一性索引.
7、 !=導(dǎo)致索引失效
?
select ui.user_name
? from user_info ui--員工信息表
? where ui.student_id!=0
在Where中使用!=將會(huì)把索引失效
8、%導(dǎo)致的索引失效
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.look_code Like '%12'/*look_code為索引,索引將失效*/
而
select di.description student_name
????? ,(select res.order_num--排名
???????? from result res
??????? where res.student_id = di.student_id
??????? order by result_math) order_num
? from description_info di
????? ,student_info???? si --學(xué)生信息表
where si.student_id = di.lookup_code(+)
?? and di.lookup_type(+) = 'STUDENT_ID'
?? and di.look_code Like '12%'/*索引有效*/
以上只例子,具體還是要針對(duì)各個(gè)不同的具體的業(yè)務(wù)使用
五、oracle 中的not Exists與Not in的性能巨大差異
Not Exists與Not in的作用同樣是排除數(shù)據(jù),在oracle 中使用not in并不象mysql中的執(zhí)行那么快,如(
select jt1.doc_num --單據(jù)號(hào)碼
????? ,oalc.description school_name --學(xué)校名稱
????? ,oalc2.description system_name --系名稱
????? ,oalc.description class_name --班級(jí)名稱
? from java_table1??????????? jt1
????? ,java_table_description oalc
????? ,java_table_description oalc2
????? ,java_table_description oalc3
where oalc.lookup_type(+) = 'JAVA_SCHOOL_NAME'
?? and jt1.school_id = oalc.lookup_code(+)
?? and oalc2.lookup_type(+) = 'JAVA_SYSTEM_NAME'
?? and jt1.system_id = oalc2.lookup_code(+)
?? and oalc3.lookup_type(+) = 'JAVA_CLASS_NAME'
?? and jt1.class_id = oalc3.lookup_code(+)
?? and not exists
(select jt2.header_id
????????? from java_table2 jt2 jt1.header_id = jt2.header_id))
與
select jt1.doc_num --單據(jù)號(hào)碼
????? ,oalc.description school_name --學(xué)校名稱
????? ,oalc2.description system_name --系名稱
????? ,oalc.description class_name --班級(jí)名稱
? from java_table1??????????? jt1
????? ,java_table_description oalc
????? ,java_table_description oalc2
????? ,java_table_description oalc3
where oalc.lookup_type(+) = 'JAVA_SCHOOL_NAME'
?? and jt1.school_id = oalc.lookup_code(+)
?? and oalc2.lookup_type(+) = 'JAVA_SYSTEM_NAME'
?? and jt1.system_id = oalc2.lookup_code(+)
?? and oalc3.lookup_type(+) = 'JAVA_CLASS_NAME'
?? and jt1.class_id = oalc3.lookup_code(+)
?? and jt1.header_id not in (select jt2.header_id from java_table2 jt2)
當(dāng)jt2表中的數(shù)據(jù)比較大時(shí),就會(huì)出現(xiàn)巨大的差異,以上只能是我的個(gè)人理解與測(cè)試結(jié)果(java_table1 視圖測(cè)試
數(shù)據(jù)量為36749,java_table2 為300條),如有其它可相互討論
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
