目前數據庫優化需要注意的幾點問題
1. 適當增加索引,儘可能使用已有的索引字段
如:
SELECT count(*) AS record_count
FROM (SELECT resume_id, name, gender, substr((sysdate - birthday) / 365, 1,
2) AS age, whcd_id, resident_area
FROM z_resumes
WHERE 1 = 1
AND resident_area = '010'
AND whcd_id = '30'
AND substr((sysdate - birthday) / 365, 1, 2) = 25);
增加索引idx_z_resumes_resident_area on z_resumes (resident_area)
如:
SELECT cid FROM insu_comp_baseinfo WHERE zzjgdm = :1
增加索引idx_insu_comp_zzjgdm on CITQUERY.insu_comp_baseinfo (zzjgdm)
如:
select *
from z_companies
where short_name = '愛筵餐飲'
增加索引IDX_Z_COMPANIES_SHORTNAME ON Z_COMPANIES (SHORT_NAME)
對部分語句建議使用索引字段
如:
select *
from sysm_busilog
where user_name = :"SYS_B_0"
and to_char(time,:"SYS_B_1") = :"SYS_B_2"
建議在類似上述的SQL語句中,用user_id替換user_name,減少對的全表掃描,因爲user_id字段上建有索引
2. 索引字段不要用函數或表達式作用,否則將不使用索引
如:
SELECT WHCD
FROM PERSON_INFO
WHERE UPPER(ZJHM) = :b1
建議去掉UPPER函數,改爲ZJHM = :b1
如:
SELECT COMPANIES.COMPANY_ID AS COMPANY_ID,
COMPANIES.REGISTER_COMPANY_CODE AS REGISTER_COMPANY_CODE,
CORPORATION.DWQC AS NAME,COMPANIES.MAN_IN_CHARGE AS
MAN_IN_CHARGE,COMPANIES.CONTACT_ADDRESS AS CONTACT_ADDRESS,
COMPANIES.POSTAL_CODE AS POSTAL_CODE,COMPANIES.DWLB_ID AS
DWLB_ID,COMPANIES.DWLX_ID AS DWLX_ID,
COMPANIES.REGISTER_ADDRESS AS REGISTER_ADDRESS,
COMPANIES.EMPLOYEE AS EMPLOYEE,COMPANIES.REGISTER_FUND AS
REGISTER_FUND,COMPANIES.REGISTER_YEAR_LIMIT AS
REGISTER_YEAR_LIMIT,COMPANIES.CONTACT_MAN AS CONTACT_MAN,
COMPANIES.TELEPHONE AS TELEPHONE,COMPANIES.INVESTORS AS
INVESTORS,COMPANIES.OTHER_CONTACTS AS OTHER_CONTACTS,
COMPANIES.DESCRIPTION AS DESCRIPTION,COMPANIES.ACTIVE_FLAG AS
ACTIVE_FLAG,COMPANIES.BE_CREATED_DATE AS BE_CREATED_DATE,
COMPANIES.LAST_UPDATED_DATE AS LAST_UPDATED_DATE,
COMPANIES.PUBLIC_FLAG AS PUBLIC_FLAG,COMPANIES.COMPANY_TYPE
AS COMPANY_TYPE,COMPANIES.IS_OUTER_FLAG AS IS_OUTER_FLAG,
COMPANIES.AGENCY_DISTRICT_ID AS AGENCY_DISTRICT_ID,
COMPANIES.SCOPE AS SCOPE
FROM Z_COMPANIES COMPANIES,CORPORATION CORPORATION,
COMPANY_PASSWORD COMPANY_PASSWORD
WHERE COMPANIES.COMPANY_ID=14560403
AND
COMPANIES.REGISTER_COMPANY_CODE=UPPER(CORPORATION.DWZZJGDM)
AND CORPORATION.CID=COMPANY_PASSWORD.CID
建議去掉UPPER,改爲COMPANIES.REGISTER_COMPANY_CODE=CORPORATION.DWZZJGDM
如:
where to_char(time,'yyyymm')='200501'
建議儘可能不要使用DATE數據類型,因爲一使用to_char函數作用就不用索引.
對於上述語句可酌情改爲where time>=to_date('200501','yyyymm') and time<to_date('200502','yyyymm')
如:
select count(*) as record_count from
(SELECT POSITION.SALARY1 ||'-'|| POSITION.SALARY2 AS SALARY,
POSITION.YZSLCD_ID_2 AS YZSLCD_ID2,
POSITION.MIN_AGE ||'-'|| POSITION.MAX_AGE AS AGE,
POSITION.POSITION_ID AS POSITION_ID,
POSITION.NAME as POSITION_NAME,POSITION.WHCD_ID AS WHCD_NAME,
POSITION.TOTAL_NUMBER AS TOTAL_NUMBER,
POSITION.DIC_CITY_AND_AREA_ID_1 AS DIC_CITY_AND_AREA_NAME_1,
DIC_UNIT_PROPERTY.DWXZ_NAME as DWXZ_NAME,
POSITION.IS_ZJ AS IS_ZJ,POSITION.ZJ_ZZJGDM AS ZJ_ZZJGDM,
to_char(POSITION.be_created_date,'YY-MM-DD') as BE_CREATED_DATE,
POSITION.IS_ZJS
FROM Z_POSITIONS POSITION,DIC_UNIT_PROPERTY
WHERE (DIC_UNIT_PROPERTY.DWXZ_ID = POSITION.DWXZ_ID)
AND to_char(POSITION.BE_CREATED_DATE,'yyyymmdd')<=to_char(sysdate,'yyyymmdd')
AND (SUBSTR(position.DIC_STATION_POSITION_ID,1,4)='0002') AND (POSITION.HISTORY_FLAG='N')
AND (POSITION.ACTIVE_FLAG='Y') AND POSITION.END_DATE >= trunc(sysdate) AND POSITION.FULL_FLAG>0 );
建議將條件(SUBSTR(position.DIC_STATION_POSITION_ID,1,4)='0002')
改爲position.DIC_STATION_POSITION_ID like '0002%')
3. 避免系統隱含的數據類型轉換
如:
SELECT cid,pid
FROM COG_ROSTER_ANNUAL_W
WHERE cid=200008010754371
若cid爲NUMBER數據類型,請使用cid=200008010754371,若cid爲CHAR數據類型,請使用cid='200008010754371',
否則系統將自動進行數據類型轉換,導致全表掃描而不使用索引
4. 儘可能減少不必要的語句
如:部分程序
先select count(*) from icq_payment where pid=:a1;
再select * from icq_payment where pid=:a1;
建議:可以直接執行後一條語句,輔以查詢不到的意外處理.
5. 儘量用簡單的語句,及減少不必要的判斷條件
如:
select max(dh)
from mail_record group by bh having bh='2005020666';
儘量避免使用GROUP BY,HAVING等複雜子句,可使用下列語句達到同樣效果:
select max(dh)
from mail_record where bh='2005020666';
如:
Select count(*)
From ICQ_PAYMENT
Where (QSNY <= ZZNY or ZZNY is null)
and pid='200008029162760'
該語句爲查詢社保個人繳費信息,點擊率非常高,
而實際上QSNY永遠=ZZNY,所以條件(QSNY <= ZZNY or ZZNY is null)沒有意義,白白浪費CPU運算
6. 中文檢索
對於中文查詢,如姓名,單位名稱,其他各類中文名稱等,若業務需求允許,儘可能要求漢字必須從頭輸入.
如將條件position.name LIKE '%駕駛員%',改成position.name LIKE '駕駛員%',則可使用position表上name字段的索引,
若兩頭模糊查詢,則只能全表掃描.將損失很多性能。
7. 特殊情況下,增加註釋,強制使用索引
有些情況下系統選擇的執行計劃會不正確,如會選擇使用全表掃描,而不使用索引,但經測試發現實際上使用索引效率高得多,
這時可強制使用索引:
如:
select count(*)
from mail_record,dic_status
where mail_record.zt = dic_status.status_id
and mail_record.scbj =0
and mail_record.zt ='0000';
測試發現,雖然mail_record上的zt字段有索引,但系統未使用,而進行全表掃描,
建議改爲
select /*+ INDEX(A,IDX_MAIL_RECORD_ZT) */ count(*)
from mail_record A,dic_status B
where A.zt = B.status_id
and A.scbj =0
and A.zt ='0000';
在select後面增加的hint (/*+ INDEX(A,IDX_MAIL_RECORD_ZT) */) 的意思是
強制使用別名爲A的mail_record表上的索引IDX_MAIL_RECORD_ZT.(在此種情況下一定要使用表的別名)
強制使用索引一定要經過測試.在沒有把握或不能確定的情況下,儘可能不要使用hint,尤其是rule hint,即/*+ RULE */, 而讓系統自己選擇執行計劃,因爲在絕大部分情況下,系統選擇執行計劃還是相當不錯的. 當確定要使用某種hint時,一定要經過測試.
補充資料:
在維護查詢的性能時,我覺得選擇得體的優化方法應該是個要注意的問題。oracle在早期的版本中最新運用的是基於規則優化器(RBO),從ORACLE 7開始引入了基於開銷(成本)優化器(CBO),從此,也就有了analyze工具,它爲表或索引生成統計和估計資料。
在INIT.ORA中可以爲數據庫設置確省的優化設置:optimizer_mode,在會話中可以動態的改變優化器模式,如set session set optimizer_goal.。oracle提供了四種優化模式:
(1)。 rule:選擇oracle使用基於規則的優化。如果我們試圖使用RBO對SQL語句進行優化時,可以設置爲RULE。請注意,RBO經常不能選擇最優的執行計劃,因爲它不能夠選擇最佳的索引
(2)。 CHOOSE:這是ORACLE的默認方式,它會根據是否能夠找到統計數字來決定使用那種優化方式,如果沒有統計數字的話,它會使用RULE;如果存在統計數字的話,它會根據是否存在索引等信息選擇使用FIRST_ROW還是ALL_ROWS。當統計資料不完整時,比如說有的表有,另外一些沒有,那麼CHOOSE會使用基於成本的優化器,並且在運行是對另外的表做統計和估計,從而影響了效率,甚至導致嚴重的效率下降問題。
(3)。 FIRST_ROW:使用CBO,它能快速返回最初的幾行,因爲它通常使用完全索引掃描,從而會造成總體效率降低或者消耗更多的系統資源。往往適合於一些ONLINE系統,因爲人們總是希望儘快看到反映。
(4)。 ALL_ROWS:它也是用CBO,但它的不表示是總體反應時間縮短,因爲它通常使用並行全表掃描,而不使用完全索引掃描
另外,可以使用HINTS,在部分語句級指定優化方式
8.在確定字段類型時,應準確選擇
- 儘可能少用date類型;
- 若放數字,應使用number類型,而不要使用char類型,避免混入異常字符;
-字段的長度儘可能估算準確,避免過長,導致空間浪費;