1. 理解ROWID
ROWID是由Oracle自動加在表中每行最后的一列偽列,既然是偽列,就說明表中並不會物理存儲ROWID的值;你可以像使用其它列一樣使用它,只是不能對該列的值進行增、刪、改操作;一旦一行數據插入后,則其對應的ROWID在該行的生命周期內是唯一的,即使發生行遷移,該行的ROWID值也不變。
SELECT t.rowid,t.* FROM DM_COMM_PREM_LIST t where LIST_ID= '3106355531';
2. SQL優化器優化方式
1)基於規則的優化器RBO(Rule-Based Optimization)
RBO有嚴格的使用規則,只要按照這套規則去寫SQL語句,無論數據表中的內容怎樣,也不會影響到你的執行計划;換句話說,RBO對數據“不敏感”,它要求SQL編寫人員必須要了解各項細則;RBO一直沿用至ORACLE 9i,從ORACLE 10g開始,RBO已經徹底被拋棄。
2)基於成本的優化器CBO(Cost-Based Optimization)
CBO是一種比RBO更加合理、可靠的優化器,在ORACLE 10g中完全取代RBO;CBO通過計算各種可能的執行計划的“代價”,即COST,從中選用COST最低的執行方案作為實際運行方案;它依賴數據庫對象的統計信息,統計信息的准確與否會影響CBO做出最優的選擇,也就是對數據“敏感”。
3. 基於SQL優化器創建有效復合索引
3.1)INDEX SKIP SCAN(復合索引之索引跳躍掃描)
Oracle 9i后提供,有時候復合索引的前導列(索引包含的第一列)沒有在查詢語句中出現,oralce也會使用該復合索引,
這時候就使用的INDEX SKIP SCAN;
3.2)什么時候會觸發 INDEX SKIP SCAN
前提條件:表有一個復合索引,且在查詢時有除了前導列(索引中第一列)外的其他列作為條件,並且優化器模式為CBO時當Oracle發現前導列的唯一值個數很少時,會將每個唯一值都作為常規掃描的入口,在此基礎上做一次查找,最后合並這些查詢;
例如:
假設表emp有ename(雇員名稱)、job(職位名)、sex(性別)三個字段,並且建立了如 create index idx_emp on emp (sex, ename, job) 的復合索引;因為性別只有 '男' 和 '女' 兩個值,所以為了提高索引的利用率,Oracle可將這個復合索引拆成 ('男', ename, job),('女', ename, job)這兩個復合索引;當查詢 select * from emp where job = 'Programmer' 時該查詢發出后: Oracle先進入sex為'男'的入口,這時候使用到了 ('男', ename, job) 這條復合索引,查找 job = 'Programmer' 的條目;再進入sex為'女'的入口,這時候使用到了 ('女', ename, job) 這條復合索引,查找 job = 'Programmer' 的條目;最后合並查詢到的來自兩個入口的結果集。
3.3)創建滿足索引跳躍掃描條件的復合索引(含日期字段)后,但是查看執行計划卻發現並未走復合索引
如:創建索引跳躍掃描 create index IDX_DM_FINISHTIME_ORGANID on DM_COMM_PREM_LIST (FINISH_TIME,ORGAN_ID) ;
查詢執行計划如下圖,發現未會走復合索引
如何解決此問題:修改日期設定的格式T1.FINISH_TIME >= TO_DATE('2017-06-01', 'yyyy-mm-ddhh24miss') AND T1.FINISH_TIME <= TO_DATE('2017-06-23', 'yyyy-mm-ddhh24miss');通過將傳入參數格式化成對應yyyy-mm-ddhh24miss格式字符串,這樣由Oracle將字符串轉成Date類型,就很順利的走索引區間掃描。效果如下:
參看博文:http://programdolt.iteye.com/blog/1186690
4.不走索引的原因,大概有如下8種:
1)建立組合索引,但查詢謂詞並未使用組合索引的第一列,此處有一個INDEX SKIP SCAN概念。
2)在包含有null值的table列上建立索引,當時使用select count(*) from table時不會使用索引。
3)在索引列上使用函數時不會使用索引,如果一定要使用索引只能建立函數索引。
如:Where條件中對字段增加處理函數將不使用該列的索引
select * from emp where to_char(hire_date,'yyyymmdd')='20080411' (不使用)
select * from emp where hire_date = to_char('20080411','yyyymmdd') (使用)
4)當被索引的列進行隱式的類型轉換時不會使用索引。
示例1:
select * from t where indexed_column = 5,而indexed_column列建立索引但類型是字符型,這時Oracle會產生隱式的類型轉換,轉換后的語句類似於select * from t where to_number(indexed_column) = 5,此時不走索引的情況類似於case3
示例2:日期轉換也有類似問題
select * from t where trunc(date_col) = trunc(sysdate)其中date_col為索引列,這樣寫不會走索引,可改寫成select * from t where date_col >= trunc(sysdate) and date_col < trunc(sysdate+1),此查詢會走索引。
5)並不是所有情況使用索引都會加快查詢速度,full scan table 有時會更快,尤其是當查詢的數據量占整個表的比重較大時,因為full scan table采用的是多塊讀,
當Oracle優化器沒有選擇使用索引時不要立即強制使用,要充分證明使用索引確實查詢更快時再使用強制索引。
6)<>
7)like’%dd’百分號在前
8)not in ,not exist
oracle中的索引掃描共計5種,本章只介紹INDEX SKIP SCAN(索引跳躍掃描),其他四種索引掃描會在另外章節總結。
INDEX UNIQUE SCAN(索引唯一掃描)
INDEX RANGE SCAN(索引范圍掃描)
INDEX FULL SCAN(索引全掃描)
INDEX FAST FULL SCAN(索引快速掃描)
參看博文:
https://www.cnblogs.com/sthinker/p/6080307.html
https://www.cnblogs.com/Dreamer-1/p/6076440.html