sql語句的最佳化
大家都在討論關於資料庫最佳化方面的東東,剛好參與開發了一個資料倉儲方面的專案,以下的一點東西算是資料庫最佳化方面的學習+實戰的一些心得體會了,拿出來大家共享。歡迎批評指正阿!
SQL語句:
是對資料庫(資料)進行操作的惟一途徑;
消耗了70%~90%的資料庫資源;獨立於程式設計邏輯,相對於對程式原始碼的最佳化,對SQL語句的最佳化在時間成本和風險上的代價都很低;
可以有不同的寫法;易學,難精通。
SQL最佳化:
固定的SQL書寫習慣,相同的查詢儘量保持相同,儲存過程的效率較高。
應該編寫與其格式一致的語句,包括字母的大小寫、標點符號、換行的位置等都要一致
ORACLE最佳化器:
在任何可能的時候都會對錶達式進行評估,並且把特定的語法結構轉換成等價的結構,這麼做的原因是
要麼結果表示式能夠比源表示式具有更快的速度
要麼源表示式只是結果表示式的一個等價語義結構
不同的SQL結構有時具有同樣的操作(例如:= ANY (subquery) and IN (subquery)),ORACLE會把他們對映到一個單一的語義結構。
1 常量最佳化:
常量的計算是在語句被最佳化時一次性完成,而不是在每次執行時。下面是檢索月薪大於2000的的表示式:
sal > 24000/12
sal > 2000
sal*12 > 24000
如果SQL語句包括第一種情況,最佳化器會簡單地把它轉變成第二種。
最佳化器不會簡化跨越比較符的表示式,例如第三條語句,鑑於此,應儘量寫用常量跟欄位比較檢索的表示式,而不要將欄位置於表示式當中。否則沒有辦法最佳化,比如如果sal上有索引,第一和第二就可以使用,第三就難以使用。
2 運算子最佳化:
最佳化器把使用LIKE運算子和一個沒有萬用字元的表示式組成的檢索表示式轉換為一個“=”運算子表示式。
例如:最佳化器會把表示式ename LIKE 'SMITH'轉換為ename = 'SMITH'
最佳化器只能轉換涉及到可變長資料型別的表示式,前一個例子中,如果ENAME欄位的型別是CHAR(10), 那麼最佳化器將不做任何轉換。
一般來講LIKE比較難以最佳化。
其中:
~~ IN 運算子最佳化:
最佳化器把使用IN比較符的檢索表示式替換為等價的使用“=”和“OR”運算子的檢索表示式。
例如,最佳化器會把表示式ename IN ('SMITH','KING','JONES')替換為
ename = 'SMITH' OR ename = 'KING' OR ename = 'JONES‘
~~ ANY和SOME 運算子最佳化:
最佳化器將跟隨值列表的ANY和SOME檢索條件用等價的同等運算子和“OR”組成的表示式替換。
例如,最佳化器將如下所示的第一條語句用第二條語句替換:
sal > ANY (:first_sal, :second_sal)
sal > :first_sal OR sal > :second_sal
最佳化器將跟隨子查詢的ANY和SOME檢索條件轉換成由“EXISTS”和一個相應的子查詢組成的檢索表示式。
例如,最佳化器將如下所示的第一條語句用第二條語句替換:
x > ANY (SELECT sal FROM emp WHERE job = 'ANALYST')
EXISTS (SELECT sal FROM emp WHERE job = 'ANALYST' AND x > sal)
~~ ALL運算子最佳化:
最佳化器將跟隨值列表的ALL運算子用等價的“=”和“AND”組成的表示式替換。例如:
sal > ALL (:first_sal, :second_sal)表示式會被替換為:
sal > :first_sal AND sal > :second_sal
對於跟隨子查詢的ALL表示式,最佳化器用ANY和另外一個合適的比較符組成的表示式替換。例如
x > ALL (SELECT sal FROM emp WHERE deptno = 10) 替換為:
NOT (x <= ANY (SELECT sal FROM emp WHERE deptno = 10))
接下來最佳化器會把第二個表示式適用ANY表示式的轉換規則轉換為下面的表示式:
NOT EXISTS (SELECT sal FROM emp WHERE deptno = 10 AND x <= sal)
~~ BETWEEN 運算子最佳化:
最佳化器總是用“>=”和“<=”比較符來等價的代替BETWEEN運算子。
例如:最佳化器會把表示式sal BETWEEN 2000 AND 3000用sal >= 2000 AND sal <= 3000來代替。
~~ NOT 運算子最佳化:
最佳化器總是試圖簡化檢索條件以消除“NOT”邏輯運算子的影響,這將涉及到“NOT”運算子的消除以及代以相應的比較運算子。
例如,最佳化器將下面的第一條語句用第二條語句代替:
NOT deptno = (SELECT deptno FROM emp WHERE ename = 'TAYLOR')
deptno <> (SELECT deptno FROM emp WHERE ename = 'TAYLOR')
通常情況下一個含有NOT運算子的語句有很多不同的寫法,最佳化器的轉換原則是使“NOT”運算子後邊的子句儘可能的簡單,即使可能會使結果表示式包含了更多的“NOT”運算子。
例如,最佳化器將如下所示的第一條語句用第二條語句代替:
NOT (sal < 1000 OR comm IS NULL)
NOT sal < 1000 AND comm IS NOT NULL sal >= 1000 AND comm IS NOT NULL
如何編寫高效的SQL:
當然要考慮sql常量的最佳化和運算子的最佳化啦,另外,還需要:
1 合理的索引設計:
例:表record有620000行,試看在不同的索引下,下面幾個SQL的執行情況:
語句A
SELECT count(*) FROM record
WHERE date >'19991201' and date < '19991214‘ and amount >2000
語句B
SELECT count(*) FROM record
WHERE date >'19990901' and place IN ('BJ','SH')
語句C
SELECT date,sum(amount) FROM record
group by date
1 在date上建有一個非聚集索引
A:(25秒)
B:(27秒)
C:(55秒)
分析:
date上有大量的重複值,在非聚集索引下,資料在物理上隨機存放在資料頁上,在範圍查詢時,必須執行一次表掃描才能找到這一範圍內的全部行。
2 在date上的一個聚集索引
A:(14秒)
B:(14秒)
C:(28秒)
分析:
在聚集索引下,資料在物理上按順序在資料頁上,重複值也排列在一起,因而在範圍查詢時,可以先找到這個範圍的起末點,且只在這個範圍內掃描資料頁,避免了大範圍掃描,提高了查詢速度。
3 在place,date,amount上的組合索引
A:(26秒)
C:(27秒)
B:(< 1秒)
分析:
這是一個不很合理的組合索引,因為它的前導列是place,第一和第二條SQL沒有引用place,因此也沒有利用上索引;第三個SQL使用了place,且引用的所有列都包含在組合索引中,形成了索引覆蓋,所以它的速度是非常快的。
4 在date,place,amount上的組合索引
A: (< 1秒)
B:(< 1秒)
C:(11秒)
分析:
這是一個合理的組合索引。它將date作為前導列,使每個SQL都可以利用索引,並且在第一和第三個SQL中形成了索引覆蓋,因而效能達到了最優。
總結1
預設情況下建立的索引是非聚集索引,但有時它並不是最佳的;合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:
有大量重複值、且經常有範圍查詢(between, >,< ,>=,< =)和order by、group by發生的列,考慮建立聚集索引;
經 常同時存取多列,且每列都含有重複值可考慮建立組合索引;在條件表示式中經常用到的不同值較多的列上建立檢索,在不同值少的列上不要建立索引。比如在僱員 表的“性別”列上只有“男”與“女”兩個不同值,因此就無必要建立索引。如果建立索引不但不會提高查詢效率,反而會嚴重降低更新速度。
組合索引要儘量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。
2 避免使用不相容的資料型別:
例如float和INt、char和varchar、bINary和varbINary是不相容的。資料型別的不相容可能使最佳化器無法執行一些本來可以進行的最佳化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在這條語句中,如salary欄位是money型的,則最佳化器很難對其進行最佳化,因為60000是個整型數。我們應當在程式設計時將整型轉化成為錢幣型,而不要等到執行時轉化。
3 IS NULL 與IS NOT NULL:
不 能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列就會從索引中排 除。也就是說如果某列存在空值,即使對該列建索引也不會提高效能。任何在WHERE子句中使用is null或is not null的語句最佳化器是不允 許使用索引的。
4 IN和EXISTS:
EXISTS要遠比IN的效率高。裡面關係到full table scan和range scan。幾乎將所有的IN運算子子查詢改寫為使用EXISTS的子查詢。
例子:
語句1
SELECT dname, deptno FROM dept
WHERE deptno NOT IN
(SELECT deptno FROM emp);
語句2
SELECT dname, deptno FROM dept
WHERE NOT EXISTS
(SELECT deptno FROM emp
WHERE dept.deptno = emp.deptno);
明顯的,2要比1的執行效能好很多
因為1中對emp進行了full table scan,這是很浪費時間的操作。而且1中沒有用到emp的INdex,
因為沒有WHERE子句。而2中的語句對emp進行的是range scan。
5 IN、OR子句常會使用工作表,使索引失效:
如果不產生大量重複值,可以考慮把子句拆開。拆開的子句中應該包含索引。
6 避免或簡化排序:
應當簡化或避免對大型表進行重複的排序。當能夠利用索引自動以適當的次序產生輸出時,最佳化器就避免了排序的步驟。以下是一些影響因素:
索引中不包括一個或幾個待排序的列;
group by或order by子句中列的次序與索引的次序不一樣;
排序的列來自不同的表。
為了避免不必要的排序,就要正確地增建索引,合理地合併資料庫表(儘管有時可能影響表的規範化,但相對於效率的提高是值得的)。如果排序不可避免,那麼應當試圖簡化它,如縮小排序的列的範圍等。
7 消除對大型錶行資料的順序存取:
在 巢狀查詢中,對錶的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個巢狀3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢 10億行資料。避免這種情況的主要方法就是對連線的列進行索引。例如,兩個表:學生表(學號、姓名、年齡??)和選課表(學號、課程號、成績)。如果兩個 表要做連線,就要在“學號”這個連線欄位上建立索引。
還可以使用並集來避免順序存取。儘管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫最佳化器使用順序存取。下面的查詢將強迫對orders表執行順序操作:
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
雖然在customer_num和order_num上建有索引,但是在上面的語句中最佳化器還是使用順序存取路徑掃描整個表。因為這個語句要檢索的是分離的行的集合,所以應該改為如下語句:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
這樣就能利用索引路徑處理查詢。
8 避免相關子查詢:
一個列的標籤同時在主查詢和WHERE子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢巢狀層次越多,效率越低,因此應當儘量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉儘可能多的行。
9 避免困難的正規表示式:
MATCHES和LIKE關鍵字支援萬用字元匹配,技術上叫正規表示式。但這種匹配特別耗費時間。例如:SELECT * FROM customer WHERE zipcode LIKE “98_ _ _”
即使在zipcode欄位上建立了索引,在這種情況下也還是採用順序掃描的方式。如果把語句改為SELECT * FROM customer WHERE zipcode >“98000”,在執行查詢時就會利用索引來查詢,顯然會大大提高速度。
另外,還要避免非開始的子串。例如語句:SELECT * FROM customer WHERE zipcode[2,3] >“80”,在WHERE子句中採用了非開始子串,因而這個語句也不會使用索引。
10 不充份的連線條件:
例:表card有7896行,在card_no上有一個非聚集索引,表account有191122行,在account_no上有一個非聚集索引,試看在不同的表連線條件下,兩個SQL的執行情況:
SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no
(20秒)
將SQL改為:
SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no and a.account_no=b.account_no
(< 1秒)
分析:
在第一個連線條件下,最佳查詢方案是將account作外層表,card作內層表,利用card上的索引,其I/O次數可由以下公式估算為:
外層表account上的22541頁+(外層表account的191122行*內層表card上對應外層表第一行所要查詢的3頁)=595907次I/O
在第二個連線條件下,最佳查詢方案是將card作外層表,account作內層表,利用account上的索引,其I/O次數可由以下公式估算為:
外層表card上的1944頁+(外層表card的7896行*內層表account上對應外層表每一行所要查詢的4頁)= 33528次I/O
可見,只有充份的連線條件,真正的最佳方案才會被執行。
多表操作在被實際執行前,查詢最佳化器會根據連線條件,列出幾組可能的連線方案並從中找出系統開銷最小的最佳方案。連線條件要充份考慮帶有索引的表、行數多的表;內外表的選擇可由公式:外層表中的匹配行數*內層表中每一次查詢的次數確定,乘積最小為最佳方案。
不可最佳化的WHERE子句
例1
下列SQL條件語句中的列都建有恰當的索引,但執行速度卻非常慢:
SELECT * FROM record WHERE substrINg(card_no,1,4)='5378'
(13秒)
SELECT * FROM record WHERE amount/30< 1000
(11秒)
SELECT * FROM record WHERE convert(char(10),date,112)='19991201'
(10秒)
分析:
WHERE子句中對列的任何操作結果都是在SQL執行時逐列計算得到的,因此它不得不進行表搜尋,而沒有使用該列上面的索引;如果這些結果在查詢編譯時就能得到,那麼就可以被SQL最佳化器最佳化,使用索引,避免表搜尋,因此將SQL重寫成下面這樣:
SELECT * FROM record WHERE card_no like '5378%'
(< 1秒)
SELECT * FROM record WHERE amount< 1000*30
(< 1秒)
SELECT * FROM record WHERE date= '1999/12/01'
(< 1秒)
11 儲存過程中,採用臨時表最佳化查詢:
例
1.從parven表中按vendor_num的次序讀資料:
SELECT part_num,vendor_num,price FROM parven ORDER BY vendor_num
INTO temp pv_by_vn
這個語句順序讀parven(50頁),寫一個臨時表(50頁),並排序。假定排序的開銷為200頁,總共是300頁。
2.把臨時表和vendor表連線,把結果輸出到一個臨時表,並按part_num排序:
SELECT pv_by_vn,* vendor.vendor_num FROM pv_by_vn,vendor
WHERE pv_by_vn.vendor_num=vendor.vendor_num
ORDER BY pv_by_vn.part_num
INTO TMP pvvn_by_pn
DROP TABLE pv_by_vn
這 個查詢讀取pv_by_vn(50頁),它透過索引存取vendor表1.5萬次,但由於按vendor_num次序排列,實際上只是透過索引順序地讀 vendor表(40+2=42頁),輸出的表每頁約95行,共160頁。寫並存取這些頁引發5*160=800次的讀寫,索引共讀寫892頁。
3.把輸出和part連線得到最後的結果:
SELECT pvvn_by_pn.*,part.part_desc FROM pvvn_by_pn,part
WHERE pvvn_by_pn.part_num=part.part_num
DROP TABLE pvvn_by_pn
這樣,查詢順序地讀pvvn_by_pn(160頁),透過索引讀part表1.5萬次,由於建有索引,所以實際上進行1772次磁碟讀寫,最佳化比例為30∶1。
好了,搞定。
其實sql的最佳化,各種資料庫之間都是互通的。
影響SQL server效能的關鍵三個方面(轉貼)
關鍵詞:Sql Server
轉貼自:
1 邏輯資料庫和表的設計
資料庫的邏輯設計、包括表與表之間的關係是最佳化關係型資料庫效能的核心。一個好的邏輯資料庫設計可以為
最佳化資料庫和應用程式打下良好的基礎。
標準化的資料庫邏輯設計包括用多的、有相互關係的窄表來代替很多列的長資料表。下面是一些使用標準化
表的一些好處。
A:由於表窄,因此可以使排序和建立索引更為迅速
B:由於多表,所以多鏃的索引成為可能
C:更窄更緊湊的索引
D:每個表中可以有少一些的索引,因此可以提高insert update delete等的速度,因為這些操作在索引
多的情況下會對系統效能產生很大的影響
E:更少的空值和更少的多餘值,增加了資料庫的緊湊性
由於標準化,所以會增加了在獲取資料時引用表的數目和其間的連線關係的複雜性。太多的表和複雜的連線關係會降低伺服器的效能,因此在這兩者之間需要綜合考慮。
定義具有相關關係的主鍵和外來鍵時應該注意的事項主要是:用於連線多表的主鍵和參考的鍵要有相同的資料型別。
2 索引的設計
A:儘量避免表掃描
檢查你的查詢語句的where子句,因為這是最佳化器重要關注的地方。包含在where裡面的每一列(column)都是可能的侯選索引,為能達到最優的效能,考慮在下面給出的例子:對於在where子句中給出了column1這個列。
下面的兩個條件可以提高索引的最佳化查詢效能!
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列
避免定義多索引而column1是第二個或後面的索引,這樣的索引不能最佳化伺服器效能
例如:下面的例子用了pubs資料庫。
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = 'White'
按下面幾個列上建立的索引將會是對最佳化器有用的索引
?au_lname
?au_lname, au_fname
而在下面幾個列上建立的索引將不會對最佳化器起到好的作用
?au_address
?au_fname, au_lname
考慮使用窄的索引在一個或兩個列上,窄索引比多索引和複合索引更能有效。用窄的索引,在每一頁上
將會有更多的行和更少的索引級別(相對與多索引和複合索引而言),這將推進系統效能。
對於多列索引,SQL Server維持一個在所有列的索引上的密度統計(用於聯合)和在第一個索引上的
histogram(柱狀圖)統計。根據統計結果,如果在複合索引上的第一個索引很少被選擇使用,那麼最佳化器對很多查詢請求將不會使用索引。
有用的索引會提高select語句的效能,包括insert,uodate,delete。
但是,由於改變一個表的內容,將會影響索引。每一個insert,update,delete語句將會使效能下降一些。實驗表明,不要在一個單表上用大量的索引,不要在共享的列上(指在多表中用了參考約束)使用重疊的索引。
在某一列上檢查唯一的資料的個數,比較它與表中資料的行數做一個比較。這就是資料的選擇性,這比較結果將會幫助你決定是否將某一列作為侯選的索引列,如果需要,建哪一種索引。你可以用下面的查詢語句返回某一列的不同值的數目。
select count(distinct cloumn_name) from table_name
假設column_name是一個10000行的表,則看column_name返回值來決定是否應該使用,及應該使用什麼索引。
Unique values Index
5000 Nonclustered index
20 Clustered index
3 No index
鏃索引和非鏃索引的選擇
<1:>鏃索引是行的物理順序和索引的順序是一致的。頁級,低層等索引的各個級別上都包含實際的資料頁。一個表只能是有一個鏃索引。由於update,delete語句要求相對多一些的讀操作,因此鏃索引常常能加速這樣的操作。在至少有一個索引的表中,你應該有一個鏃索引。
在下面的幾個情況下,你可以考慮用鏃索引:
例如: 某列包括的不同值的個數是有限的(但是不是極少的)
顧客表的州名列有50個左右的不同州名的縮寫值,可以使用鏃索引。
例如: 對返回一定範圍內值的列可以使用鏃索引,比如用between,>,>=,<,<=等等來對列進行操作的列上。
select * from sales where ord_date between '5/1/93' and '6/1/93'
例如: 對查詢時返回大量結果的列可以使用鏃索引。
SELECT * FROM phonebook WHERE last_name = 'Smith'
當有大量的行正在被插入表中時,要避免在本表一個自然增長(例如,identity列)的列上建立鏃索引。如果你建立了鏃的索引,那麼insert的效能就會大大降低。因為每一個插入的行必須到表的最後,表的最後一個資料頁。
當一個資料正在被插入(這時這個資料頁是被鎖定的),所有的其他插入行必須等待直到當前的插入已經結束。
一個索引的葉級頁中包括實際的資料頁,並且在硬碟上的資料頁的次序是跟鏃索引的邏輯次序一樣的。
<2:>一個非鏃的索引就是行的物理次序與索引的次序是不同的。一個非鏃索引的葉級包含了指向行資料頁的指標。
在一個表中可以有多個非鏃索引,你可以在以下幾個情況下考慮使用非鏃索引。
在有很多不同值的列上可以考慮使用非鏃索引
例如:一個part_id列在一個part表中
select * from employee where emp_id = 'pcm9809f'
查詢語句中用order by 子句的列上可以考慮使用鏃索引
3 查詢語句的設計
SQL Server最佳化器透過分析查詢語句,自動對查詢進行最佳化並決定最有效的執行方案。最佳化器分析查詢語句來決定那個子句可以被最佳化,並針對可以被最佳化查詢的子句來選擇有用的索引。最後最佳化器比較所有可能的執行方案並選擇最有效的一個方案出來。
在執行一個查詢時,用一個where子句來限制必須處理的行數,除非完全需要,否則應該避免在一個表中無限制地讀並處理所有的行。
例如下面的例子,
select qty from sales where stor_id=7131
是很有效的比下面這個無限制的查詢
select qty from sales
避免給客戶的最後資料選擇返回大量的結果集。允許SQL Server執行滿足它目的的函式限制結果集的大小是更有效的。
這能減少網路I/O並能提高多使用者的相關併發時的應用程式效能。因為最佳化器關注的焦點就是where子句的查詢,以利用有用的索引。在表中的每一個索引都可能成為包括在where子句中的侯選索引。為了最好的效能可以遵照下面的用於一個給定列column1的索引。
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列不要在where子句中使用沒有column1列索引的查詢語句,並避免在where子句用一個多索引的非第一個索引的索引。
這時多索引是沒有用的。
For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in
the pubs database,
下面這個query語句利用了au_lname上的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = 'White'
AND au_fname = 'Johnson'
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = 'White'
下面這個查詢沒有利用索引,因為他使用了多索引的非第一個索引的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_fname = 'Johnson'
小結:
1.對查詢進行最佳化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
3.應儘量避免在 where 子句中使用!=或<>運算子,否則將引擎放棄使用索引而進行全表掃描。
4.應儘量避免在 where 子句中使用 or 來連線條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
5.in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。
7.如果在 where 子句中使用引數,也會導致全表掃描。因為SQL只有在執行時才會解析區域性變數,但最佳化程式不能將訪問計劃的選擇推遲到執行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8.應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2
9.應儘量避免在where子句中對欄位進行函式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate
10.不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。
11.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)
13.很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
14.並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢最佳化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
16.應儘可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的物理儲存順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。
17.儘量使用數字型欄位,若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。這是因為引擎在處理查詢和連線時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。
18.儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。
19.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
20.儘量使用表變數來代替臨時表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。
21.避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。
22.臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。
23.在新建臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。
24.如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
25.儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。
26.使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
27.與臨時表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的儲存過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行儲存過程和觸發器的每個語句後向客戶端傳送 DONE_IN_PROC 訊息。
29.儘量避免大事務操作,提高系統併發能力。
30.儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。
具體的SQL語句在很多情況下需要結合實際的應用情況來寫,這裡不作敘述。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/143526/viewspace-1024737/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 最佳化sql語句SQL
- SQL語句最佳化SQL
- sql最佳化:使用sql profile最佳化sql語句SQL
- SQL Profiles與語句最佳化SQL
- SQL語句運算子最佳化SQL
- 效能最佳化之SQL語句最佳化SQL
- 對sql語句的最佳化問題SQL
- SQL語句最佳化技術分析SQL
- ORACLE常用SQL最佳化hint語句OracleSQL
- MySQL的SQL語句最佳化一例MySql
- 資料庫最佳化技巧 - SQL語句最佳化資料庫SQL
- Oracle SQL語句最佳化技術分析OracleSQL
- straight_join最佳化sql語句AISQL
- SQL最佳化案例-單表分頁語句的最佳化(八)SQL
- Effective MySQL之SQL語句最佳化 小結MySql
- 透過分析SQL語句的執行計劃最佳化SQL(總結)SQL
- SQL語句SQL
- SQL語句IN的用法SQL
- 常用的SQL語句SQL
- 常用的SQL 語句SQL
- SQL 語句 as 的用法SQL
- oracle的sql語句OracleSQL
- Java中如何解析SQL語句、格式化SQL語句、生成SQL語句?JavaSQL
- [轉]透過分析SQL語句的執行計劃最佳化SQL(總結)SQL
- 第45期:一條 SQL 語句最佳化的基本思路SQL
- spark sql語句效能最佳化及執行計劃SparkSQL
- sql 中的with 語句使用SQL
- SQL語句的優化SQL優化
- sql語句的簡化SQL
- 實用的SQL語句~!SQL
- sql語句大全SQL
- 共享SQL語句SQL
- SQL語句整理SQL
- SQL基本語句SQL
- 精妙Sql語句SQL
- SQL語句集合SQL
- oracle sql語句OracleSQL
- sql語句 求救!SQL