Oracle中的一些查詢語句及其執行順序
原文地址:https://www.cnblogs.com/likeju/p/5039115.htmlhtml
查詢條件:
1)LIKE:模糊查詢,須要藉助兩個通配符,%:表示0到多個字符;_:標識單個字符。
2)IN(list):用來取出符合列表範圍中的數據。
3)NOT IN(list): 取出不符合此列表中的數據記錄。
4)BETWEEN…AND…:用來查詢符合某個值域範圍條件的數據,最多見的是使用在數字類型的數據範圍上,但對字符類型和日期類型數據也一樣適用。for example: SELECT ename, sal FROM emp WHERE sal BETWEEN 1500 AND 3000;
5)IS NULL:空值NULL是一個特殊的值,比較的時候不能使用」=」號,必須使用IS NULL,不然不能獲得正確的結果。
6)IS NOT NULL:與5相反。
7) >ANY : 大於最小 <ANY:小於最大 >ALL:大於最大 <ALL:小於最小
for example: SELECT empno, ename, job, sal, deptno FROM emp WHERE sal > ANY (345,3333,123)
8)DISTINCT:過濾重複。for example: SELECT DISTINCT deptno FROM emp
9)ORDER BY:對查詢出的數據按必定規則進行排序操做,ASC指定升序,DESC指定降序。
10)GROUP BY:把獲得的數據按照給定的字段進行分組,例如:把整個數據表按部門劃分紅一個個小組。
11)HAVING:HAVING子句用來對分組後的結果進一步限制,好比按部門分組後,獲得每一個部門的最高薪水,能夠繼續限制輸出結果。必須跟在GROUP BY後面,不能單獨存在。例如: SELECT deptno, MAX(sal) max_sal FROM emp GROUP BY deptno HAVING MAX(sal) >4000;
查詢語句的執行順序:
一、FROM 子句:執行順序爲從後往前、從右到左。數據量較少的表儘可能放在後面。
二、WHERE子句:執行順序爲自下而上、從右到左。將能過濾掉最大數量記錄的條件寫在WHERE 子句的最右。
三、GROUP BY:執行順序從左往右分組,最好在GROUP BY前使用WHERE將不須要的記錄在GROUP BY以前過濾掉。
四、HAVING 子句:消耗資源。儘可能避免使用,HAVING 會在檢索出全部記錄以後纔對結果集進行過濾,須要排序等操做。
五、SELECT子句:少用*號,儘可能取字段名稱。ORACLE 在解析的過程當中, 經過查詢數據字典將*號依次轉換成全部的列名, 消耗時間。
六、ORDER BY子句:執行順序爲從左到右排序,消耗資源。程序員
Select 語句執行順序以及如何提升Oracle 基本查詢效率
原文地址:https://www.cnblogs.com/likeju/p/5039128.htmlsql
今天把這幾天作的練習複習了一下,不知道本身寫得代碼執行的效率如何以及要如何提升,因而乎上網開始研究一些材料,現整理以下:數據庫
首先,要了解在Oracle中Sql語句運行的機制。如下是sql語句的執行步驟:
1)語法分析,分析語句的語法是否符合規範,衡量語句中各表達式的意義。
2)語義分析,檢查語句中涉及的全部數據庫對象是否存在,且用戶有相應的權限。
3)視圖轉換,將涉及視圖的查詢語句轉換爲相應的對基表查詢語句。
4)表達式轉換, 將複雜的 SQL 表達式轉換爲較簡單的等效鏈接表達式。
5)選擇優化器,不一樣的優化器通常產生不一樣的「執行計劃」
6)選擇鏈接方式, ORACLE 有三種鏈接方式,對多表鏈接 ORACLE 可選擇適當的鏈接方式。
7)選擇鏈接順序, 對多表鏈接 ORACLE 選擇哪一對錶先鏈接,選擇這兩表中哪一個表作爲源數據表。
8)選擇數據的搜索路徑,根據以上條件選擇合適的數據搜索路徑,如是選用全表搜索仍是利用索引或是其餘的方式。
9)運行「執行計劃」。編程
這裏不得不提的是Oracle共享原理:將執行過的SQL語句存放在內存的共享池(shared buffer pool)中,能夠被全部的數據庫用戶共享當你執行一個SQL語句(有時被稱爲一個遊標)時,若是它和以前的執行過的語句徹底相同, Oracle就能很快得到已經被解析的語句以及最好的 執行路徑. 這個功能大大地提升了SQL的執行性能並節省了內存的使用。服務器
在瞭解了SQL語句的運行機制與Oracle共享原理後,咱們能夠知道SQL語句的書寫方式對SQL語句的執行效率有很大的影響。那麼下面咱們瞭解一下SQL中Select語句中各個關鍵字執行的順序。網絡
SQL語言不一樣於其餘編程語言的最明顯特徵是處理代碼的順序。在大多數據庫語言中,代碼按編碼順序被處理。但在SQL語句中,第一個被處理的子句是FROM,而不是第一齣現的SELECT。SQL查詢處理的步驟序號:
(8) SELECT (9) DISTINCT (11) <TOP_specification> <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE | ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
以上每一個步驟都會產生一個虛擬表,該虛擬表被用做下一個步驟的輸入。這些虛擬表對調用者(客戶端應用程序或者外部查詢)不可用。只有最後一步生成的表纔會會給調用者。若是沒有在查詢中指定某一個子句,將跳過相應的步驟。
邏輯查詢處理階段簡介:
一、 FROM:對FROM子句中的前兩個表執行笛卡爾積(交叉聯接),生成虛擬表VT1。表名執行順序是從後往前,因此數據較少的表儘可能放後。
二、 ON:對VT1應用ON篩選器,只有那些使爲真才被插入到TV2。
三、 OUTER (JOIN):若是指定了OUTER JOIN(相對於CROSS JOIN或INNER JOIN),保留表中未找到匹配的行將做爲外部行添加到VT2,生成TV3。若是FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1到步驟3,直處處理完全部的表位置。
四、 WHERE:對TV3應用WHERE篩選器,只有使爲true的行才插入TV4。執行順序爲從前日後或者說從左到右。
五、 GROUP BY:按GROUP BY子句中的列列表對TV4中的行進行分組,生成TV5。執行順序從左往右分組。
六、 CUTE|ROLLUP:把超組插入VT5,生成VT6。
七、 HAVING:對VT6應用HAVING篩選器,只有使爲true的組插入到VT7。Having語句很耗資源,儘可能少用 八、 SELECT:處理SELECT列表,產生VT8。
九、 DISTINCT:將重複的行從VT8中刪除,產品VT9。
十、ORDER BY:將VT9中的行按ORDER BY子句中的列列表順序,生成一個遊標(VC10)。執行順序從左到右,是一個很耗資源的語句。
十一、TOP:從VC10的開始處選擇指定數量或比例的行,生成表TV11,並返回給調用者。併發
看到這裏,應該是清楚了整個SQL語句整個執行的過程,那麼咱們就接下來進一步要坐得就是在實現功能同時有考慮性能的思想,努力提升SQL的執行效率。oracle
第1、只返回須要的數據
返回數據到客戶端至少須要數據庫提取數據、網絡傳輸數據、客戶端接收數據以及客戶端處理數據等環節,若是返回不須要的數據,就會增長服務器、網絡和客戶端的無效勞動,其害處是顯而易見的,避免這類事件須要注意: 編程語言
A、橫向來看,
(1)不要寫SELECT *的語句,而是選擇你須要的字段。
(2)當在SQL語句中鏈接多個表時, 請使用表的別名並把別名前綴於每一個Column上.這樣一來,就能夠減小解析的時間並減小那些由Column歧義引發的語法錯誤。
B、縱向來看,
(1)合理寫WHERE子句,不要寫沒有WHERE的SQL語句。
(2) SELECT TOP N * --沒有WHERE條件的用此替代
第2、儘可能少作重複的工做
A、控制同一語句的屢次執行,特別是一些基礎數據的屢次執行是不少程序員不多注意的。
B、減小屢次的數據轉換,也許須要數據轉換是設計的問題,可是減小次數是程序員能夠作到的。
C、杜毫不必要的子查詢和鏈接表,子查詢在執行計劃通常解釋成外鏈接,多餘的鏈接錶帶來額外的開銷。
D、合併對同一表同一條件的屢次UPDATE。
E、UPDATE操做不要拆成DELETE操做+INSERT操做的形式,雖然功能相同,可是性能差異是很大的。
第3、注意臨時表和表變量的用法
在複雜系統中,臨時表和表變量很難避免,關於臨時表和表變量的用法,須要注意:
A、若是語句很複雜,鏈接太多,能夠考慮用臨時表和表變量分步完成。
B、若是須要屢次用到一個大表的同一部分數據,考慮用臨時表和表變量暫存這部分數據。
C、若是須要綜合多個表的數據,造成一個結果,能夠考慮用臨時表和表變量分步彙總這多個表的數據。
D、其餘狀況下,應該控制臨時表和表變量的使用。
E、關於臨時表和表變量的選擇,不少說法是表變量在內存,速度快,應該首選表變量,可是在實際使用中發現,(1)主要考慮須要放在臨時表的數據量,在數據量較多的狀況下,臨時表的速度反而更快。(2)執行時間段與預計執行時間(多長)
F、關於臨時表產生使用SELECT INTO和CREATE TABLE + INSERT INTO的選擇,通常狀況下,SELECT INTO會比CREATE TABLE + INSERT INTO的方法快不少,可是SELECT INTO會鎖定TEMPDB的系統表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用戶併發環境下,容易阻塞其餘進程,因此個人建議是,在併發系統中,儘可能使用CREATE TABLE + INSERT INTO,而大數據量的單個語句使用中,使用SELECT INTO。
第4、注意子查詢的用法
子查詢是一個 SELECT 查詢,它嵌套在 SELECT、INSERT、UPDATE、DELETE 語句或其它子查詢中。任何容許使用表達式的地方均可以使用子查詢,子查詢可使咱們的編程靈活多樣,能夠用來實現一些特殊的功能。可是在性能上,每每一個不合適的子查詢用法會造成一個性能瓶頸。若是子查詢的條件中使用了其外層的表的字段,這種子查詢就叫做相關子查詢。
相關子查詢能夠用IN、NOT IN、EXISTS、NOT EXISTS引入。 關於相關子查詢,應該注意:
(1)
A、NOT IN、NOT EXISTS的相關子查詢能夠改用LEFT JOIN代替寫法。
好比:
SELECT PUB_NAME
FROM PUBLISHERS
WHERE PUB_ID NOT IN (SELECT PUB_ID FROM TITLES WHERE TYPE = 'BUSINESS')
能夠改寫成:
SELECT A.PUB_NAME
FROM PUBLISHERS A LEFT JOIN TITLES B ON B.TYPE = 'BUSINESS' AND A.PUB_ID=B. PUB_ID
WHERE B.PUB_ID IS NULL
(2)
SELECT TITLE
FROM TITLES
WHERE NOT EXISTS (SELECT TITLE_ID FROM SALES WHERE TITLE_ID = TITLES.TITLE_ID)
能夠改寫成:
SELECT TITLE
FROM TITLES LEFT JOIN SALES ON SALES.TITLE_ID = TITLES.TITLE_ID
WHERE SALES.TITLE_ID IS NULL
B、 若是保證子查詢沒有重複 ,IN、EXISTS的相關子查詢能夠用INNER JOIN 代替。
好比:
SELECT PUB_NAME
FROM PUBLISHERS
WHERE PUB_ID IN (SELECT PUB_ID FROM TITLES
WHERE TYPE = 'BUSINESS')
能夠改寫成:
SELECT DISTINCT A.PUB_NAME
FROM PUBLISHERS A INNER JOIN TITLES B ON B.TYPE = 'BUSINESS' AND A.PUB_ID=B. PUB_ID
C、 IN的相關子查詢用EXISTS代替,好比
SELECT PUB_NAME
FROM PUBLISHERS
WHERE PUB_ID IN (SELECT PUB_ID FROM TITLES WHERE TYPE = 'BUSINESS')
能夠用下面語句代替:
SELECT PUB_NAME
FROM PUBLISHERS
WHERE EXISTS (SELECT 1 FROM TITLES WHERE TYPE = 'BUSINESS' AND PUB_ID= PUBLISHERS.PUB_ID) D、不要用COUNT(*)的子查詢判斷是否存在記錄,最好用LEFT JOIN或者EXISTS,好比有人寫這樣的語句:
SELECT JOB_DESC
FROM JOBS
WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0
應該改爲:
SELECT JOBS.JOB_DESC
FROM JOBS LEFT JOIN EMPLOYEE ON EMPLOYEE.JOB_ID=JOBS.JOB_ID
WHERE EMPLOYEE.EMP_ID IS NULL
SELECT JOB_DESC FROM JOBS WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)<>0
應該改爲:
SELECT JOB_DESC FROM JOBS
WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)
第5、儘可能使用索引,並注意對含索引列的運算
創建索引後,並非每一個查詢都會使用索引,在使用索引的狀況下,索引的使用效率也會有很大的差異。只要咱們在查詢語句中沒有強制指定索引,索引的選擇和使用方法是SQLSERVER的優化器自動做的選擇,而它選擇的根據是查詢語句的條件以及相關表的統計信息,這就要求咱們在寫SQL語句的時候儘可能使得優化器可使用索引。爲了使得優化器能高效使用索引,寫語句的時候應該注意:
A、不要對索引字段進行運算,而要想辦法作變換,好比
SELECT ID FROM T WHERE NUM/2=100
應改成:
SELECT ID FROM T WHERE NUM=100*2
-------------------------------------------------------
SELECT ID FROM T WHERE NUM/2=NUM1
若是NUM有索引應改成:
SELECT ID FROM T WHERE NUM=NUM1*2
若是NUM1有索引則不該該改。
--------------------------------------------------------------------
發現過這樣的語句:
SELECT 年,月,金額 FROM 結餘表 WHERE 100*年+月=2010*100+10
應該改成:
SELECT 年,月,金額 FROM 結餘表 WHERE 年=2010 AND月=10
B、 不要對索引字段進行格式轉換
日期字段的例子:
WHERE CONVERT(VARCHAR(10), 日期字段,120)='2010-07-15'
應該改成
WHERE日期字段〉='2010-07-15' AND 日期字段<'2010-07-16' IS NULL
轉換的例子:
WHERE ISNULL(字段,'')<>''應改成:WHERE字段<>'
WHERE ISNULL(字段,'')=''不該修改
WHERE ISNULL(字段,'F') ='T'應改成: WHERE字段='T'
WHERE ISNULL(字段,'F')<>'T'不該修改
C、 不要對索引字段使用函數
WHERE LEFT(NAME, 3)='ABC' 或者WHERE SUBSTRING(NAME,1, 3)='ABC'
應改成: WHERE NAME LIKE 'ABC%'
日期查詢的例子:
WHERE DATEDIFF(DAY, 日期,'2010-06-30')=0
應改成:WHERE 日期>='2010-06-30' AND 日期 <'2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')>0
應改成:WHERE 日期 <'2010-06-30'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')>=0
應改成:WHERE 日期 <'2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')<0
應改成:WHERE 日期>='2010-07-01'
WHERE DATEDIFF(DAY, 日期,'2010-06-30')<=0
應改成:WHERE 日期>='2010-06-30'
D、不要對索引字段進行多字段鏈接
好比:
WHERE FAME+ '. '+LNAME='HAIWEI.YANG'
應改成:
WHERE FNAME='HAIWEI' AND LNAME='YANG'
第6、注意多表鏈接的鏈接條件的選擇與表示
多表鏈接的鏈接條件對索引的選擇有着重要的意義,因此咱們在寫鏈接條件條件的時候須要特別注意。
A、多表鏈接的時候,鏈接條件必須寫全,寧肯重複,不要缺漏。
B、鏈接條件儘可能使用匯集索引
C、注意ON、WHERE和HAVING部分條件的區別: ON是最早執行, WHERE次之,HAVING最後,由於ON是先把不符合條件的記錄過濾後才進行統計,它就能夠減小中間運算要處理的數據,按理說應該速度是最快的,WHERE也應該比 HAVING快點的,由於它過濾數據後才進行SUM,在兩個表聯接時才用ON的,因此在一個表的時候,就剩下WHERE跟HAVING比較了
一、考慮聯接優先順序:
二、INNER JOIN
三、LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)
四、CROSS JOIN
其它注意和了解的地方有:
A、在IN後面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最後面,減小判斷的次數
B、注意UNION和UNION ALL的區別。--容許重複數據用UNION ALL好
C、注意使用DISTINCT,在沒有必要時不要用
D、TRUNCATE TABLE 與 DELETE 區別
E、減小訪問數據庫的次數
還有就是咱們寫存儲過程,若是比較長的話,最後用標記符標開,由於這樣可讀性很好,即便語句寫的不怎麼樣可是語句工整。如:
--startof 查詢在職人數
sql語句
--end of
正式機器上咱們通常不能隨便調試程序,可是不少時候程序在咱們本機上沒問題,可是進正式系統就有問題,可是咱們又不能隨便在正式機器上操做,那麼怎麼辦呢?咱們能夠用回滾來調試咱們的存儲過程或者是sql語句,從而排錯。
BEGIN TRAN
UPDATE a SET 字段=' '
ROLLBACK
做業存儲過程能夠加上下面這段,這樣檢查錯誤能夠放在存儲過程,若是執行錯誤回滾操做,可是若是程序裏面已經有了事務回滾,那麼存儲過程就不要寫事務了,這樣會致使事務回滾嵌套下降執行效率,可是咱們不少時候能夠把檢查放在存儲過程裏,這樣有利於咱們解讀這個存儲過程,和排錯。
BEGIN TRANSACTION
--事務回滾開始
--檢查報錯
IF ( @@ERROR > 0 )
BEGIN
--回滾操做
ROLLBACK TRANSACTION
RAISERROR('刪除工做報告錯誤', 16, 3)
RETURN
END
--結束事務
COMMIT TRANSACTION
第7、有效使用Decode函數
使用Decode函數能夠有效避免重複掃描相同數據或重複鏈接相同表。
以上就是此次的總結了,參考了不少文檔,網絡是個好平臺,感謝你們的分享
ORACLE中where部分條件執行順序測試
實驗1:證實oracle SQL的語法分析應該是從右到左的
測試語句
--語句1 Select 'ok' From Dual Where 1 / 0 = 1 And 1 = 2; --語句2 Select 'ok' From Dual Where 1 = 2 And 1 / 0 = 1;
- --語句1
Select '測試' From Dual Where 1 / 0 = 1 And 1 = 2; - 查詢結果不會報錯
--語句2
Select '測試' From Dual Where 1 = 2 And 1 / 0 = 1; - 查詢結果會報錯
語句1不會報錯,語句2報錯
結果:證實了oracle SQL條件的執行是從右到左的