1.書寫格式
示例代碼:
存儲過程SQL文書寫格式例
select
c.dealerCode,
round(sum(c.submitSubletAmountDLR + c.submitPartsAmountDLR + c.submitLaborAmountDLR) / count(*), 2) as avg,
decode(null, 'x', 'xx', 'CNY')
from (
select
a.dealerCode,
a.submitSubletAmountDLR,
a.submitPartsAmountDLR,
a.submitLaborAmountDLR
from SRV_TWC_F a
where (to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'
and to_char(a.ORIGSUBMITTIME, 'yyyy/mm/dd') <= 'Date Range(end)'
and nvl(a.deleteflag, '0') <> '1')
union all
select
b.dealerCode,
b.submitSubletAmountDLR,
b.submitPartsAmountDLR,
b.submitLaborAmountDLR
from SRV_TWCHistory_F b
where (to_char(b.ORIGSUBMITTIME, 'yyyy/mm/dd') >= 'Date Range(start)'
and to_char(b.ORIGSUBMITTIME,'yyyy/mm/dd') <= 'Date Range(end)'
and nvl(b.deleteflag,'0') <> '1')
) c
group by c.dealerCode
order by avg desc;
java source里的SQL字符串書寫格式例
strSQL = "insert into Snd_FinanceHistory_Tb "
+ "(DEALERCODE, "
+ "REQUESTSEQUECE, "
+ "HANDLETIME, "
+ "JOBFLAG, "
+ "FRAMENO, "
+ "INMONEY, "
+ "REMAINMONEY, "
+ "DELETEFLAG, "
+ "UPDATECOUNT, "
+ "CREUSER, "
+ "CREDATE, "
+ "HONORCHECKNO, "
+ "SEQ) "
+ "values ('" + draftInputDetail.dealerCode + "', "
+ "'" + draftInputDetail.requestsequece + "', "
+ "sysdate, "
+ "'07', "
+ "'" + frameNO + "', "
+ requestMoney + ", "
+ remainMoney + ", "
+ "'0', "
+ "0, "
+ "'" + draftStrUCt.employeeCode + "', "
+ "sysdate, "
+ "'" + draftInputDetail.honorCheckNo + "', "
+ index + ")";
1).縮進
對于存儲過程文件,縮進為8個空格
對于Java source里的SQL字符串,不可有縮進,即每一行字符串不可以空格開頭
2).換行
1>.Select/From/Where/Order by/Group by等子句必須另其一行寫
2>.Select子句內(nèi)容假如只有一項,與Select同行寫
3>.Select子句內(nèi)容假如多于一項,每一項單獨占一行,在對應(yīng)Select的基礎(chǔ)上向右縮進8個空格(Java source無縮進)
4>.From子句內(nèi)容假如只有一項,與From同行寫
5>.From子句內(nèi)容假如多于一項,每一項單獨占一行,在對應(yīng)From的基礎(chǔ)上向右縮進8個空格(Java source無縮進)
6>.Where子句的條件假如有多項,每一個條件占一行,以AND開頭,且無縮進
7>.(Update)Set子句內(nèi)容每一項單獨占一行,無縮進
8>.Insert子句內(nèi)容每個表字段單獨占一行,無縮進;values每一項單獨占一行,無縮進
9>.SQL文中間不答應(yīng)出現(xiàn)空行
10>.Java source里單引號必須跟所屬的SQL子句處在同一行,連接符("+")必須在行首
3).空格
1>.SQL內(nèi)算數(shù)運算符、邏輯運算符連接的兩個元素之間必須用空格分隔
2>.逗號之后必須接一個空格
3>.要害字、保留字和左括號之間必須有一個空格
2.不等于統(tǒng)一使用"<>"
Oracle認(rèn)為"!="和"<>"是等價的,都代表不等于的意義。
為了統(tǒng)一,不等于一律使用"<>"表示
3.使用表的別名
數(shù)據(jù)庫查詢,必須使用表的別名
4.SQL文對表字段擴展的兼容性
在Java source里使用Select *時,嚴(yán)禁通過getString(1)的形式得到查詢結(jié)果,必須使用getString("字段名")的形式
使用Insert時,必須指定插入的字段名,嚴(yán)禁不指定字段名直接插入values
5.減少子查詢的使用
子查詢除了可讀性差之外,還在一定程度上影響了SQL運行效率
請盡量減少使用子查詢的使用,用其他效率更高、可讀性更好的方式替代
6.適當(dāng)添加索引以提高查詢效率
適當(dāng)添加索引可以大幅度的提高檢索速度
請參看Oracle SQL性能優(yōu)化系列
7.對數(shù)據(jù)庫表操作的非凡要求
本項目對數(shù)據(jù)庫表的操作還有以下非凡要求:
1).以邏輯刪除替代物理刪除
注重:現(xiàn)在數(shù)據(jù)庫表中數(shù)據(jù)沒有物理刪除,只有邏輯刪除
以deleteflag字段作為刪除標(biāo)志,deleteflag='1'代表此記錄被邏輯刪除,因此在查詢數(shù)據(jù)時必須考慮deleteflag的因素
deleteflag的標(biāo)準(zhǔn)查詢條件:NVL(deleteflag, '0') <> '1'
2).增加記錄狀態(tài)字段
數(shù)據(jù)庫中的每張表基本都有以下字段:DELETEFLAG、UPDATECOUNT、CREDATE、CREUSER、UPDATETIME、UPDATEUSER
要注重在對標(biāo)進行操作時必須考慮以下字段
插入一條記錄時要置DELETEFLAG='0', UPDATECOUNT=0, CREDATE=sysdate, CREUSER=登錄User
查詢一條記錄時要考慮DELETEFLAG,假如有可能對此記錄作更新時還要取得UPDATECOUNT作同步檢查
修改一條記錄時要置UPDATETIME=sysdate, UPDATEUSER=登錄User, UPDATECOUNT=(UPDATECOUNT+1) mod 1000,
刪除一條記錄時要置DELETEFLAG='1'
3).歷史表
數(shù)據(jù)庫里部分表還存在相應(yīng)的歷史表,比如srv_twc_f和srv_twchistory_f
在查詢數(shù)據(jù)時除了檢索所在表之外,還必須檢索相應(yīng)的歷史表,對二者的結(jié)果做Union(或Union All)
8.用執(zhí)行計劃分析SQL性能
EXPLAIN PLAN是一個很好的分析SQL語句的工具,它可以在不執(zhí)行SQL的情況下分析語句
通過分析,我們就可以知道ORACLE是怎樣連接表,使用什么方式掃描表(索引掃描或全表掃描),以及使用到的索引名稱
按照從里到外,從上到下的次序解讀分析的結(jié)果
EXPLAIN PLAN的分析結(jié)果是用縮進的格式排列的,最內(nèi)部的操作將最先被解讀,假如兩個操作處于同一層中,帶有最小操作號的將首先被執(zhí)行
目前許多第三方的工具如PLSQL Developer和TOAD等都提供了極其方便的EXPLAIN PLAN工具
PG需要將自己添加的查詢SQL文記入log,然后在EXPLAIN PLAN中進行分析,盡量減少全表掃描
ORACLE SQL性能優(yōu)化系列
1.選擇最有效率的表名順序(只在基于規(guī)則的優(yōu)化器中有效)
ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最后的表(基礎(chǔ)表driving table)將被最先處理
在FROM子句中包含多個表的情況下,必須選擇記錄條數(shù)最少的表作為基礎(chǔ)表
當(dāng)ORACLE處理多個表時,會運用排序及合并的方式連接它們
首先,掃描第一個表(FROM子句中最后的那個表)并對記錄進行排序;
然后掃描第二個表(FROM子句中最后第二個表);
最后將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合并
例如:
表 TAB1 16,384 條記錄
表 TAB2 5 條記錄
選擇TAB2作為基礎(chǔ)表 (最好的方法)
select count(*) from tab1,tab2 執(zhí)行時間0.96秒
選擇TAB2作為基礎(chǔ)表 (不佳的方法)
select count(*) from tab2,tab1 執(zhí)行時間26.09秒
假如有3個以上的表連接查詢,那就需要選擇交叉表(intersection table)作為基礎(chǔ)表,交叉表是指那個被其他表所引用的表
例如:
EMP表描述了LOCATION表和CATEGORY表的交集
SELECT *
FROM LOCATION L,
CATEGORY C,
EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
將比下列SQL更有效率
SELECT *
FROM EMP E ,
LOCATION L ,
CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
2.WHERE子句中的連接順序
ORACLE采用自下而上的順序解析WHERE子句
根據(jù)這個原理,表之間的連接必須寫在其他WHERE條件之前,那些可以過濾掉最大數(shù)量記錄的條件必須寫在WHERE子句的末尾
例如:
(低效,執(zhí)行時間156.3秒)
SELECT *
FROM EMP E
WHERE SAL > 50000
AND JOB = 'MANAGER'
AND 25 <
(SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);
(高效,執(zhí)行時間10.6秒)
SELECT *
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = 'MANAGER';
3.SELECT子句中避免使用'*'
當(dāng)你想在SELECT子句中列出所有的COLUMN時,使用動態(tài)SQL列引用'*'是一個方便的方法,不幸的是,這是一個非常低效的方法
實際上,ORACLE在解析的過程中,會將'*'依次轉(zhuǎn)換成所有的列名
這個工作是通過查詢數(shù)據(jù)字典完