oracle中sql語句的優化(轉帖)
本文轉載之http://www.cnblogs.com/netjxz/archive/2009/09/21/1570991.html
一、執行順序及優化細則
1.表名順序優化
(1) 基礎表放下面,當兩表進行關聯時資料量少的表的表名放右邊
表或檢視:
Student_info (30000條資料)
Description_info (30條資料)
select *
from description_info di
,student_info si --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
與
select *
from student_info si--學生資訊表
,description_info di
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
以student_info作為基礎表,你會發現執行的速度會有很大的差距。
(2) 當出現多個表時,關聯表被稱之為交叉表,交叉表作為基礎表
select *
from description_info di
,description_info di2
,student_info si --學生資訊表
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--學生資訊表
,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作為基礎表,你會發現執行的速度會有很大的差距,
當基礎表放在後面,這樣的執行速度會明顯快很多。
2.where執行順序
where執行會從至下往上執行
select *
from student_info si --學生資訊表
where si.school_id=10 --學院ID
and si.system_id=100--系ID
擺放where子句時,把能過濾大量資料的條件放在最下邊
3. is null 和is not null
當要過濾列為空資料或不為空的資料時使用
select *
from student_info si --學生資訊表
where si.school_id is null(當前列中的null為少數時用is not null,否則is null)
4.使用表別名
當查詢時出現多個表時,查詢時加上別名,
避免出現減少解析的時間欄位歧義引起的語法錯誤。
5. where執行速度比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. * 號引起的執行效率
儘量減少使用select * 來進行查詢,當你查詢使用*,
資料庫會進行解析並將*轉換為全部列。
二、替代優化
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
執行時>=會比>執行得要快
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
上面語句可有效避免全表查詢
select ui.user_name
from user_info ui--員工資訊表
where ui.student_id=10
or ui.student_id=2
如果堅持要用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)
執行會更有效率
4、 Union All 與Union
Union All重複輸出兩個結果集合中相同記錄
如果兩個並集中資料都不一樣.那麼使用Union All 與Union是沒有區別的,
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會比Union要執行得快
5、分離表和索引
總是將你的表和索引建立在另外的表空間內
決不要將這些物件存放到SYSTEM表空間裡
三、一些優化技巧
1、計算表的記錄數時
select count(si.student_id)
from Student_info si(student_id為索引)
與
select count(*) from Student_info si
執行時.上面的語句明顯會比下面沒有用索引統計的語句要快
2.使用函式提高SQL執行速度
當出現複雜的查詢sql語名,可以考慮使用函式來提高速度
查詢學生資訊並查詢學生(李明)個人資訊與的數學成績排名
如
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.description = '李明'
而且我們將上面order_num排名寫成一個fuction時
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;
執行
select di.description student_name
,order_num_pkg.order_num(di.student_id) order_num
from description_info di
,student_info si --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.description = '李明'
執行查詢時的速度也會有所提高
3.減少訪問資料庫的次數
執行次數的減少(當要查詢出student_id=100的學生和student_id=20的學生資訊時)
select address_id
from student_info si --學生資訊表
where si.student_id=100
與
select address_id
from student_info si --學生資訊表
where si.student_id=20
都進行查詢.這樣的效率是很低的
而進行
(
select si.address_id,si2.address_id
from student_info si --學生資訊表
,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
)
執行速度是提高了,但可讀性反而差了..
所以這種寫法個人並不太推薦
4、用Exists(Not Exists)代替In(Not In)
在執行當中使用Exists或者Not Exists可以高效的進行查詢
5、Exists取代Distinct取唯一值的
取出關聯表部門對員工時,這時取出員工部門時,出現多條..
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
通過表的關聯來代替exists會使執行更有效率
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');
執行是比較快,但還可以使用表的連線取得更快的查詢效率
select ui.user_name
from departments_info di
,user_info ui --員工資訊表
where ui.dept_no = di.dept_no
and ui.department_type_code = 'IT'
程式碼是經測試並進行優化所寫,
以上只例子,具體使用還是要針對各個不同的具體的業務使用用Exists(Not Exists)代替In(Not In)
四、索引篇
1、運算導致的索引失效
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and si.student_id+0=100/*student_id索引將失效*/
2、型別轉換導致的索引失效
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.student_id='100'
student_id為number型別的索引,當執行下列語句,
oracle會自動轉換成
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.student_id=to_number('100')
所幸,只是解析並轉換型別,並沒有導到失效,
但要是寫成下面,將會使用其失效
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and to_char(di.student_id)='100'
3、在索引列上進行計算引起的問題
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.student_id-2=10
在索引列中進行運算,將會不使用索引而使用全表掃描
而將
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.student_id=10+2
將會得到高效的執行速度
4、 Is not null引起的問題(student_id為索引)
不要把存在空值的列做為索引,否則無法使用索引
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導致索引失效(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、自動選擇索引
如果表中有兩個以上(包括兩個)索引,其中有一個唯一性索引,而其他是非唯一性.
在這種情況下,ORACLE將使用唯一性索引而完全忽略非唯一性索引.
7、 !=導致索引失效
select ui.user_name
from user_info ui--員工資訊表
where ui.student_id!=0
在Where中使用!=將會把索引失效
8、%導致的索引失效
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 --學生資訊表
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 --學生資訊表
where si.student_id = di.lookup_code(+)
and di.lookup_type(+) = 'STUDENT_ID'
and di.look_code Like '12%'/*索引有效*/
以上只例子,具體還是要針對各個不同的具體的業務使用
五、oracle 中的not Exists與Not in的效能巨大差異
Not Exists與Not in的作用同樣是排除資料,在oracle 中使用not in並不象mysql中的執行那麼快,如(
select jt1.doc_num --單據號碼
,oalc.description school_name --學校名稱
,oalc2.description system_name --系名稱
,oalc.description class_name --班級名稱
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 --單據號碼
,oalc.description school_name --學校名稱
,oalc2.description system_name --系名稱
,oalc.description class_name --班級名稱
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)
當jt2表中的資料比較大時,就會出現巨大的差異,以上只能是我的個人理解與測試結果(java_table1 檢視測試
資料量為36749,java_table2 為300條),如有其它可相互討論
相關推薦
oracle中sql語句的優化(轉帖)
本文轉載之http://www.cnblogs.com/netjxz/archive/2009/09/21/1570991.html一、執行順序及優化細則1.表名順序優化 (1) 基礎表放下面,當兩表進行關聯時資料量少的表的表名放右邊表或檢視: Student_info
Oracle 中sql語句中的取前n條數據
沒有 blog tab 註意 sql table bsp num 數據 取得薪水最高的前五名員工 sql: select * from ( select empno,ename,sal from emp order by sal desc) where rownum&l
oracle中sql語句中多個查詢結果的交集、差集和並集
1.交集 intersect運算:返回查詢結果中相同的部分。 SELECT product_id FROM tab1 INTERSECT SELECT product_
ORACLE中LIKE語句優化
1。儘量不要使用 like '%%' 2。對於 like '%' (不以 % 開頭),Oracle可以應用 colunm上的index 3。對於 like '%…' 的 (不以 % 結尾),可以利用reverse + function index 的形式,變化成
ORACLE中sql語句----運算子的優先順序
算數運算子——>連線運算子——>比較(關係)運算子——>IS NULL , IS NOT NULL , LIKE , NOT LIKE , IN , NOT IN ——>BETWEEN , NOT BETWEEN ——>NOT 邏輯運算子——&g
從oracle中取時間戳轉日期格式的SQL語句
SELECT TO_CHAR(ADDTIME/ (60 * 60 * 24) + TO_DATE('1970-01-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') AS TESTDATE FR
oracle中hint的使用-SQL語句優化
表明對語句塊選擇基於開銷的優化方法,並獲得最佳吞吐量,使資源消耗最小化. 例如: SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 2. /*+FIRST_ROWS*/ 表明對語句塊選擇基於開銷的優化方
[轉]Oracle的update語句優化研究
lis 錯誤 wid class 插入 集合 top 執行 gin 原文地址:http://blog.csdn.net/u011721927/article/details/39228001 一、 update語句的語法與原理 1. 語法 單表:
SQL語句優化系列四(Oracle數據庫日期格式轉換)
fun ont 如果 etime 當前時間 字符轉換函數 dual minute nbsp Oracle數據庫日期格式轉換 select sysdate from dual select to_char(sysdate,‘yyyy/mm/dd hh24:mi:ss‘) as
數據庫性能優化之SQL語句優化(轉 java知音)
可能 資源 詳細介紹 有助於 效果 這就是 詳細 分組統計 完全 一、問題的提出 在應用系統開發初期,由於開發數據庫數據比較少,對於查詢SQL語句,復雜視圖的編寫等體會不出SQL語句各種寫法的性能優劣,但是如果將應用系統提交實際應用後,隨著數據庫中數據的增加,系統的
在外部應用中執行oracle的sql語句時出現“不支援的列資料型別”錯誤
如 SELECT OBJECTID,osmid,username,userid,versional,lat,lon,visible,changeset,timestamps,issimple,fc,dsg,code,gbcode,gbdes,tags,bz,names,n
資料庫效能之SQL語句優化(中)
百萬級資料優化 一.I_IPTVLOGIN00 (五十萬),TEMP_STBINFO (五百萬) 1.select a.loginAccount,a.stbID,b.DEV_SNO from I_IPTVLOGIN00 a,TEMP_STBINFO b where a.s
oracle的sql語句的簡單優化
執行路徑: ORACLE的這個功能大大地提高了SQL的執行效能並節省了記憶體的使用: 我們發現,單表資料的統計比多表統計的速度完全是兩個概念.單表統計可能只要0.02秒,但是2張表聯合統計就可能要幾 十表了. 這是因為ORACLE只對簡單的表提供高速緩衝(cache buffering)
oracle 編寫sql語句獲取表中的最後一條資料
select p.* from (select * from t_cfg_menu t order by t.menu_id desc) p where rownum = 1 首先查詢表中資料按降序排列,然後通過“rownum = 1”獲取第一條資料,即是原
mysql和oracle的xml的sql語句互轉
<select id="query" resultMap="resultMap">select * from role <where><if test="roleName != null and roleName != ''">and ROLE_NAME like '%'
Oracle 建立索引及利用索引的SQL語句優化
資料庫索引: 索引有單列索引 複合索引之說 如何某表的某個欄位有主鍵約束和唯一性約束,則Oracle 則會自動在相應的約束列上建議唯一索引。資料庫索引主要進行提高訪問速度。 建設原則: 1、索引應該經常建在Where 子句經常用到的列上。如果某個大表經常使用某個欄位進行
『ORACLE』 SQL語句簡單應用(四)(11g)
union times truncate sql語句 默認值 位數 lib rownum dual 排序 後加 nulls last 在降序排列中把null放在最後 select to_char(sysdate,‘q‘) from dual; dual
『ORACLE』 SQL語句簡單應用(五)(11g)
應用 11g sql cal foreign ora 每次 int pri not null 非空 字段+not null unique 唯一 primary key 主鍵(確保數據不能重復) foreign key 外鍵 check 必須
Oracle 中MERGE語句的用法(轉載)
同時 sdn ble reat nth merge type href detail 原文章出處(http://blog.csdn.net/lichkui/article/details/4306299) MERGE語句是Oracle9i新增的語法,用來合並UPDATE和I
Oracle的sql語句的兩種判斷形式
紅色 其他 num cor score ask rac res 復雜 Oracle的sql語句的兩種判斷形式 判斷當前列同時改動當前列 判斷一個情況改動其他值 一類情況詳解:實現的是當num這一列的值為3時,就顯示好 以此類推 1)case num when