1、選擇最有效率的表連接順序
首先要明白一點就是SQL 的語法順序和執行順序是不一致的
SQL的語法順序:
select 【distinct】 ....from ....【xxx join】【on】....where....group by ....having....【union】....order by......
SQL的執行順序:
from ....【xxx join】【on】....where....group by ....avg()、sum()....having....select 【distinct】....order by......
from 子句--執行順序為從后往前、從右到左
表名(最后面的那個表名為驅動表,執行順序為從后往前, 所以數據量較少的表盡量放后)
where子句--執行順序為自下而上、從右到左
將可以過濾掉大量數據的條件寫在where的子句的末尾性能最優
group by 和order by 子句執行順序都為從左到右
select子句--少用*號,盡量取字段名稱。 使用列名意味着將減少消耗時間。
2、避免產生笛卡爾積
含有多表的sql語句,必須指明各表的連接條件,以避免產生笛卡爾積。N個表連接需要N-1個連接條件。
3、避免使用*
當你想在select子句中列出所有的列時,使用動態sql列引用“*”是一個方便的方法,不幸的是,是一種非常低效的方法。sql解析過程中,還需要把“*”依次轉換為所有的列名,這個工作需要查詢數據字典完成!
4、用where子句替換having子句
where子句搜索條件在進行分組操作之前應用;而having自己條件在進行分組操作之后應用。避免使用having子句,having子句只會在檢索出所有紀錄之后才對結果集進行過濾,這個處理需要排序,總計等操作。如果能通過where子句限制記錄的數目,那就能減少這方面的開銷。
5、用exists、not exists和in、not in相互替代
原則是哪個的子查詢產生的結果集小,就選哪個
select * from t1 where x in (select y from t2)
select * from t1 where exists (select null from t2 where y =x)
IN適合於外表大而內表小的情況;exists適合於外表小而內表大的情況
6、使用exists替代distinct
當提交一個包含一對多表信息(比如部門表和雇員表)的查詢時,避免在select子句中使用distinct,一般可以考慮使用exists代替,exists使查詢更為迅速,因為子查詢的條件一旦滿足,立馬返回結果。
低效寫法:
select distinct dept_no,dept_name from dept d,emp e where d.dept_no=e.dept_no
高效寫法:
select dept_no,dept_name from dept d where exists (select 'x' from emp e where e.dept_no=d.dept_no)
備注:其中x的意思是:因為exists只是看子查詢是否有結果返回,而不關心返回的什么內容,因此建議寫一個常量,性能較高!
用exists的確可以替代distinct,不過以上方案僅適用dept_no為唯一主鍵的情況,如果要去掉重復記錄,需要參照以下寫法:
select * from emp where dept_no exists (select Max(dept_no)) from dept d, emp e where e.dept_no=d.dept_no group by d.dept_no)
7、避免隱式數據類型轉換
隱式數據類型轉換不能適用索引,導致全表掃描!t_tablename表的phonenumber字段為varchar類型
以下代碼不符合規范:
select column1 into i_l_variable1 from t_tablename where phonenumber=18519722169;
應編寫如下:
select column1 into i_lvariable1 from t_tablename where phonenumber='18519722169';
8、使用索引來避免排序操作
在執行頻度高,又含有排序操作的sql語句,建議適用索引來避免排序。排序是一種昂貴的操作,在一秒鍾執行成千上萬次的sql語句中,如果帶有排序操作,往往會消耗大量的系統資源,性能低下。索引是一種有序結果,如果order by后面的字段上建有索引,將會大大提升效率!
9、盡量使用前端匹配的模糊查詢
例如,column1 like 'ABC%'方式,可以對column1字段進行索引范圍掃描;而column1 kike '%ABC%'方式,即使column1字段上存在索引,也無法使用該索引,只能走全表掃描。
10、不要在選擇性較低的字段建立索引
在選擇性較低的字段使用索引,不但不會降低邏輯I/O,相反,往往會增加大量邏輯I/O降低性能。比如,性別列,男和女!
11、避免對列的操作
不要在where條件中對字段進行數學表達式運算,任何對列的操作都可能導致全表掃描,這里所謂的操作,包括數據庫函數,計算表達式等等,查詢時要盡可能將操作移到等式的右邊,甚至去掉函數。
例如:下列sql條件語句中的列都建有恰當的索引,但幾十萬條數據下已經執行非常慢了:
select * from record where amount/30<1000 (執行時間11s)
由於where子句中對列的任何操作結果都是在sql運行時逐行計算得到,因此它不得不進行全表掃描,而沒有使用上面的索引;如果這些結果在查詢編譯時就能得到,那么就可以被sql優化器優化,使用索引,避免全表掃描,因此sql重寫如下:
select * from record where amount<1000*30 (執行時間不到1秒)
12、盡量去掉"IN","OR"
含有"IN"、"OR"的where子句常會使用工作表,使索引失效,如果不產生大量重復值,可以考慮把子句拆開;拆開的子句中應該包含索引;
select count(*) from stuff where id_no in('0','1')
可以拆開為:
select count(*) from stuff where id_no='0'
select count(*) from stuff where id_no='1'
然后在做一個簡單的加法
13、盡量去掉"<>"
盡量去掉"<>",避免全表掃描,如果數據是枚舉值,且取值范圍固定,可以使用"or"方式
update serviceinfo set state=0 where state<>0;
以上語句由於其中包含了"<>",執行計划中用了全表掃描(Table access full),沒有用到state字段上的索引,實際應用中,由於業務邏輯的限制,字段state智能是枚舉值,例如0,1或2,因此可以去掉"<>" 利用索引來提高效率。
update serviceinfo set state=0 where state =1 or state =2
14、避免在索引列上使用IS NULL或者NOT
避免在索引中使用任何可以為空的列,導致無法使用索引
15、批量提交sql
如果你需要在一個在線的網站上去執行一個大的DELETE或INSERT查詢,你需要非常小心,要避免你的操作讓你的整個網站停止相應。因為這兩個操作是會鎖表的,表一鎖住了,別的操作都進不來了。
Apache會有很多的子進程或線程。所以,其工作起來相當有效率,而我們的服務器也不希望有太多的子進程,線程和數據庫鏈接,這是極大的占服務器資源的事情,尤其是內存。
如果你把你的表鎖上一段時間,比如30秒鍾,那么對於一個有很高訪問量的站點來說,這30秒所積累的訪問進程或線程,數據庫鏈接,打開的文件數,可能不僅僅會讓你的WEB服務崩潰,還可能會讓你的整台服務器馬上掛了。所以,如果你有一個大的處理,你一定把其拆分。
16、使用合理的分頁方式以提高分頁的效率
select id from job_queue limit 69500, 15
使用上述SQL語句做分頁的時候,隨着表數據量的增加,第一頁與最后一頁的查詢時間會越來越長,優化的方法如下:可以取前一頁的最大行數的id,然后根據這個最大的id來限制下一頁的起點。比如此列中,上一頁最大的id是69500。SQL可以采用如下的寫法:
select id,name from product where id> 69500 limit 15
17、分段查詢
在一些查詢頁面中,當用戶選擇的時間范圍過大,造成查詢緩慢。主要的原因是掃描行數過多。這個時候可以通過程序,分段進行查詢,循環遍歷,將結果合並處理進行展示。
18、不建議使用%前綴模糊查詢
例如LIKE“%name”或者LIKE“%name%”,這種查詢會導致普通索引失效而進行全表掃描,可以使用全文索引。
注: 文章來自網絡