sql優化最佳實踐


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%”,這種查詢會導致普通索引失效而進行全表掃描,可以使用全文索引。

 

注: 文章來自網絡 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM