sql優化

1、介紹

在應用系統開發初期,由於開發數據庫數據比較少,對於查詢SQL語句,複雜視圖的的編寫等體會不出SQL語句各種寫法的性能優劣,但是隨着互聯網大數據的興起,隨着數據庫中數據的增加,系統的響應速度就成爲目前系統需要解決的最主要的問題之一。

系統優化中一個很重要的方面就是SQL語句的優化。對於海量數據,劣質SQL語句和優質SQL語句之間的速度差別可以達到上百倍,可見對於一個系統不是簡單地能實現其功能就可,而是要寫出高質量的SQL語句,提高系統的可用性。

在多數情況下,Oracle使用索引來更快地遍歷表,優化器主要根據定義的索引來提高性能。但是,如果在SQL語句的where子句中寫的SQL代碼不合理,就會造成優化器刪去索引而使用全表掃描,一般就這種SQL語句就是所謂的劣質SQL語句。在編寫SQL語句時我們應清楚優化器根據何種原則來刪除索引,這有助於寫出高性能的SQL語句。我們要做到不但會寫SQL,還要做到寫出性能優良的SQL,以下是我工作,學習的經驗,彙總了部分資料與大家分享!,如發現不合理或錯誤的地方請大家及時指出來,以便大家共同成長。

2、常見優化規則

2.1 表連接數

連接的表越多,性能越差
可能的話,將連接拆分成若干個過程逐一執行
優先執行可顯著減少數據量的連接,既降低了複雜度,也能夠容易按照預期執行
如果不可避免多表連接,很可能是設計缺陷
外鏈接效果差,因爲必須對左右表進行表掃描
儘量使用inner join查詢

2.2 使用臨時表

如果不可避免,可以考慮使用臨時表或表變量存放中間結果。

2.3 少用子查詢

2.4 視圖嵌套

不要過深,一般視圖嵌套不要超過2個爲宜。

3、SQL編寫注意事項

3.1 NULL列

Null列使用索引沒有意義,任何包含null值的列都不會被包含在索引中。因此where語句中的is null或is not null的語句優化器是不允許使用索引的。

3.2 concat或||

concat或||是mysql和oracle的字符串連接操作,如果對列進行該函數操作,那麼也開會忽略索引的使用。比較下面的查詢語句:

– 忽律索引
select … from … where first_name || ‘’ || last_name = ‘bill gates’ ;
– 使用索引
select … from … where first_name = ‘bill’ and last_name = ‘bill gates’ ;

3.3 like

通配符出現在首位,無法使用索引,反之可以。

– 無法使用索引
select … from … where name like ‘%t%’ ;
– 可以使用索引
select … from … where name like ‘t%’ ;

3.4 order by

order by子句中不要使用非索引列或嵌套表達式,這樣都會導致性能降低。

3.5 Not運算

not運算無法使用索引,可以改成其他能夠使用索引的操作。如下:

– 索引無效
select … from … where sal != 3000 ;
– 索引生效
select … from … where sal < 3000 or sal > 3000;

3.6 where與having

select … from … on … where … group by … having … order by … limit …,以上是sql語句的語法結構,其中on、where和having是有過濾行爲的,過濾行爲越能提前完成就越可以減少傳遞給下一個階段的數據量,因此如果在having中的過濾行爲能夠在where中完成,則應該優先考慮where來實現。

3.7 exists替代in

not in是最低效的,因爲要對子查詢的表進行全表掃描。可以考慮使用外鏈接或not exists。如下:

– 正確
SELECT *
FROM EMP
WHERE
EMPNO > 0
AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)

– 錯誤
SELECT *
FROM EMP
WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)

3.8 索引

索引的好處可以實現折半查找,時間複雜度是
O(log2n)
,但是也有成本,需要額外的空間存放索引數據,並且每次insert、update和delete都會對索引進行更新,因此會多增加4、5次的磁盤IO。所以給一些不必要使用索引的字段增加索引,會降低系統的性能。對於oracle來講,SQL語句儘量大寫,內部需要向將小寫轉成大寫,再執行。

不要在索引列上使用函數,這樣會停止使用索引,進行全表掃描,如下:

– 錯誤
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
– 正確
SELECT … FROM DEPT WHERE SAL > 25000/12;

3.9 >與>

直接定位到4的記錄(推薦)
select … from … where SAL >= 4 ;
– 先定位到3,再向後找1個(不推薦)
select … from … where SAL > 3 ;

3.10 union代替or

在索引列上,可以使用union替換or操作。索引列上的or操作會造成全表掃描。

– 高效:
SELECT LOC_ID , LOC_DESC , REGION FROM LOCATION WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION FROM LOCATION WHERE REGION = ‘MELBOURNE’

– 低效:
SELECT LOC_ID ,LOC_DESC ,REGION FROM LOCATION WHERE LOC_ID=10 OR REGION =‘MELBOURNE’

3.11 is null & is not null

如果列可空,避免使用索引。對於多個列使用的索引,起碼保證至少有個列不爲空。對於多列索引,只有訪問了第一個列纔會啓用索引,如果訪問後面的列則使用的是全表掃描。

– 低效: (索引失效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
– 高效: (索引有效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;

3.12 union & union all

union具有去重的操作,增加了計算時間。union all不需要去重,但會包含相同記錄。同樣功能下,首選union all操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章