sql教程欄目介紹sql常用知識點。
推薦:sql教程
當然,有很多時候您需要執(zhí)行 LEFT JOIN 和使用 NULL 值。但是,它們并不適用于所有情況。改變 SQL 查詢的構(gòu)建方式可能會產(chǎn)生將一個花幾分鐘運行的報告縮短到只花幾秒鐘這樣的天壤之別的效果。有時,必須在查詢中調(diào)整數(shù)據(jù)的形態(tài),使之適應(yīng)應(yīng)用程序所要求的顯示方式。雖然 TABLE 數(shù)據(jù)類型會減少大量占用資源的情況,但在查詢中還有許多區(qū)域可以進行優(yōu)化。SQL 的一個有價值的常用功能是 LEFT JOIN。它可以用于檢索第一個表中的所有行、第二個表中所有匹配的行、以及第二個表中與第一個表不匹配的所有行。例如,如果希望返回每個客戶及其定單,使用 LEFT JOIN 則可以顯示有定單和沒有定單的客戶。
此工具可能會被過度使用。LEFT JOIN 消耗的資源非常之多,因為它們包含與 NULL(不存在)數(shù)據(jù)匹配的數(shù)據(jù)。在某些情況下,這是不可避免的,但是代價可能非常高。LEFT JOIN 比 INNER JOIN 消耗資源更多,所以如果您可以重新編寫查詢以使得該查詢不使用任何 LEFT JOIN,則會得到非常可觀的回報(請參閱圖 1 中的圖)。
sql語句中join on和where用法的區(qū)別和聯(lián)系
對于要達到同一查詢結(jié)果而言,join和where的用法是語句格式不一樣,查詢的結(jié)果是一樣的。
先來看看join的語句分類:
left join :左連接,返回左表中所有的記錄以及右表中連接字段相等的記錄。
right join :右連接,返回右表中所有的記錄以及左表中連接字段相等的記錄。
inner join: 內(nèi)連接,又叫等值連接,只返回兩個表中連接字段相等的行。
full join:外連接,返回兩個表中的行:left join + right join。
cross join:結(jié)果是笛卡爾積,就是第一個表的行數(shù)乘以第二個表的行數(shù)。
轉(zhuǎn)載自::http://www.cnblogs.com/lcngu/p/6726537.html? ? 下面這個是講解outer join 查詢?on篩選和where篩選的區(qū)別? 個人認為是正確的
在連接查詢語法中,另人迷惑首當其沖的就要屬on篩選和where篩選的區(qū)別了,? 在我們編寫查詢的時候, 篩選條件的放置不管是在on后面還是where后面, 查出來的結(jié)果總是一樣的, 既然如此,那為什么還要多此一舉的讓sql查詢支持兩種篩選器呢?? 事實上, 這兩種篩選器是存在差別的,只是如果不深挖不容易發(fā)現(xiàn)而已。
sql中的連接查詢分為3種, cross join,inner join,和outer join ,? 在 cross join和inner join中,篩選條件放在on后面還是where后面是沒區(qū)別的,極端一點,在編寫這兩種連接查詢的時候,只用on不使用where也沒有什么問題。因此,on篩選和where篩選的差別只是針對outer join,也就是平時最常使用的left join和right join。
來看一個示例,有兩張數(shù)據(jù)表,結(jié)構(gòu)和數(shù)據(jù)如圖所示
?
表main
表ext
可以把這兩張表看作是用來存放用戶信息的, main放置主要信息,ext表放置附加信息,兩張表的關(guān)系是1對1的,以id字符作為對應(yīng)關(guān)系鍵。現(xiàn)在我們需要將地址不為杭州的所有用戶信息篩選出來,結(jié)果中需要包含main表和ext表的所有字段數(shù)據(jù)。
?select * from main left JOIN? exton main.id = ext.id? and? address ‘杭州’
閉上眼睛, 請用大腦人肉運行一下這段SQL, 想象一下是什么結(jié)果。
當把?address ‘杭州’?這個篩選條件放在on之后,查詢得到的結(jié)果似乎跟我們預(yù)料中的不同,從結(jié)果中能看出,這個篩選條件好像只過濾掉了ext表中對應(yīng)的記錄,而main表中的記錄并沒有被過濾掉,也就是上圖中標記為紅色的那條記錄。outer join相對于inner join的一個主要特性就是以一側(cè)的表為基礎(chǔ),但是在這里以左表為基這一點卻可以無視篩選條件,這未免也太霸道了一些。
把查詢語句稍微改動一下,將地址的篩選條件從on轉(zhuǎn)移至where
select * from main left JOIN? ext on main.id = ext.id? where address ‘杭州’
結(jié)果就如我們預(yù)期的那樣了
造成這種結(jié)果上的差異要從outer join查詢的邏輯查詢的各個階段說起。總的來說,outer join 的執(zhí)行過程分為4步
1、先對兩個表執(zhí)行交叉連接(笛卡爾積)
2、應(yīng)用on篩選器
3、添加外部行
4、應(yīng)用where篩選器
就拿上面不使用where篩選器的sql來說,執(zhí)行的整個詳細過程如下
第一步,對兩個表執(zhí)行交叉連接,結(jié)果如下,這一步會產(chǎn)生36條記錄(此圖顯示不全)
第二步,應(yīng)用on篩選器。篩選器中有兩個條件,main.id = ext.id? and address ‘杭州’,符合要求的記錄如下
這似乎正是我們期望中查詢的結(jié)果,然而在接下來的步驟中這個結(jié)果會被打亂
第三步,添加外部行。outer join有一個特點就是以一側(cè)的表為基,假如另一側(cè)的表沒有符合on篩選條件的記錄,則以null替代。在這次的查詢中,這一步的作用就是將那條原本應(yīng)該被過濾掉的記錄給添加了回來
是不是不種畫蛇添足的感覺, 結(jié)果就成了這樣
第四步,應(yīng)用where篩選器
在這條問題sql中,因為沒有where篩選器,所以上一步的結(jié)果就是最終的結(jié)果了。
而對于那條地址篩選在where條件中的sql,這一步便起到了作用,將所有地址不屬于杭州的記錄篩選了出來
?
通過上面的講解,已經(jīng)能反應(yīng)出在outer join中的篩選條件在on中和where中的區(qū)別,開發(fā)人員如能詳細了解之中差別,能規(guī)避很多在編寫sql過程中出現(xiàn)的莫名其妙的錯誤。
轉(zhuǎn)載自::https://blog.csdn.net/wang1127248268/article/details/53413655? ?
性能不理想的系統(tǒng)中除了一部分是因為應(yīng)用程序的負載確實超過了服務(wù)器的實際處理能力外,更多的是因為系統(tǒng)存在大量的SQL語句需要優(yōu)化。
為了獲得穩(wěn)定的執(zhí)行性能,SQL語句越簡單越好。對復(fù)雜的SQL語句,要設(shè)法對之進行簡化。
常見的簡化規(guī)則如下:
?
1)不要有超過5個以上的表連接(JOIN)
2)考慮使用臨時表或表變量存放中間結(jié)果。
3)少用子查詢(可以使用 join)
4)視圖嵌套不要過深,一般視圖嵌套不要超過2個為宜。
?
連接的表越多,其編譯的時間和連接的開銷也越大,性能越不好控制。
最好是把連接拆開成較小的幾個部分逐個順序執(zhí)行。
優(yōu)先執(zhí)行那些能夠大量減少結(jié)果的連接。
拆分的好處不僅僅是減少SQL Server優(yōu)化的時間,更使得SQL語句能夠以你可以預(yù)測的方式和順序執(zhí)行。
如果一定需要連接很多表才能得到數(shù)據(jù),那么很可能意味著設(shè)計上的缺陷。
?
連接是outer join,非常不好。因為outer join意味著必須對左表或右表查詢所有行。
如果表很大而沒有相應(yīng)的where語句,那么outer join很容易導(dǎo)致table scan或index scan。
要盡量使用inner join避免scan整個表。
優(yōu)化建議:
?
1)使用臨時表存放t1表的結(jié)果,能大大減少logical reads(或返回行數(shù))的操作要優(yōu)先執(zhí)行。(個人感覺這個建議超級實用)
?仔細分析語句,你會發(fā)現(xiàn)where中的條件全是針對表t1的,所以直接使用上面的where子句查詢表t1,然后把結(jié)果存放再臨時表#t1中:
?
Select t1….. into #tt1 from t1 where…(和上面的where一樣)
?
2)再把#tt1和其他表進行連接:
?
Select #t1…
Left outer join …
Left outer join…
?
?
3)修改 like 程序,去掉前置百分號。like語句卻因為前置百分號而無法使用索引
4)從系統(tǒng)設(shè)計的角度修改語句,去掉outer join。
5)考慮組合索引或覆蓋索引消除clustered index scan。
?
上面1和2點建議立即消除了worktable,性能提高了幾倍以上,效果非常明顯。
1)限制結(jié)果集
?
要盡量減少返回的結(jié)果行,包括行數(shù)和字段列數(shù)。
返回的結(jié)果越大,意味著相應(yīng)的SQL語句的logical reads 就越大,對服務(wù)器的性能影響就越甚。
一個很不好的設(shè)計就是返回表的所有數(shù)據(jù):
?
Select * from tablename
?
即使表很小也會導(dǎo)致并發(fā)問題。更壞的情況是,如果表有上百萬行的話,那后果將是災(zāi)難性的。
它不但可能帶來極重的磁盤IO,更有可能把數(shù)據(jù)庫緩沖區(qū)中的其他緩存數(shù)據(jù)擠出,使得這些數(shù)據(jù)下次必須再從磁盤讀取。
必須設(shè)計良好的SQL語句,使得其有where語句或TOP語句來限制結(jié)果集大小。
2)合理的表設(shè)計
?
SQL Server 2005將支持表分區(qū)技術(shù)。利用表分區(qū)技術(shù)可以實現(xiàn)數(shù)據(jù)表的流動窗口功能。
在流動窗口中可以輕易的把歷史數(shù)據(jù)移出,把新的數(shù)據(jù)加入,從而使表的大小基本保持穩(wěn)定。
?
另外,表的設(shè)計未必需要非常范式化。有一定的字段冗余可以增加SQL語句的效率,減少JOIN的數(shù)目,提高語句的執(zhí)行速度。
3)OLAP和OLTP模塊要分開
?
OLAP和OLTP類型的語句是截然不同的。前者往往需要掃描整個表做統(tǒng)計分析,索引對這樣的語句幾乎沒有多少用處。
索引只能夠加快那些如sum,group by之類的聚合運算。因為這個原因,幾乎很難對OLAP類型的SQL語句進行優(yōu)化。
而OLTP語句則只需要訪問表的很小一部分數(shù)據(jù),而且這些數(shù)據(jù)往往可以從內(nèi)存緩存中得到。
為了避免OLAP 和OLTP語句相互影響,這兩類模塊需要分開運行在不同服務(wù)器上。
因為OLAP語句幾乎都是讀取數(shù)據(jù),沒有更新和寫入操作,所以一個好的經(jīng)驗是配置一臺standby 服務(wù)器,然后OLAP只訪問standby服務(wù)器。
4)使用存儲過程
可以考慮使用存儲過程封裝那些復(fù)雜的SQL語句或商業(yè)邏輯,這樣做有幾個好處。
一是存儲過程的執(zhí)行計劃可以被緩存在內(nèi)存中較長時間,減少了重新編譯的時間。
二是存儲過程減少了客戶端和服務(wù)器的繁復(fù)交互。
三是如果程序發(fā)布后需要做某些改變你可以直接修改存儲過程而不用修改程序,避免需要重新安裝部署程序。?
?索引優(yōu)化
很多數(shù)據(jù)庫系統(tǒng)性能不理想是因為系統(tǒng)沒有經(jīng)過整體優(yōu)化,存在大量性能低下的SQL 語句。
這類SQL語句性能不好的首要原因是缺乏高效的索引。
沒有索引除了導(dǎo)致語句本身運行速度慢外,更是導(dǎo)致大量的磁盤讀寫操作,使得整個系統(tǒng)性能都受之影響而變差。
解決這類系統(tǒng)的首要辦法是優(yōu)化這些沒有索引或索引不夠好的SQL語句。
創(chuàng)建索引的關(guān)鍵 ?
?
優(yōu)化SQL語句的關(guān)鍵是盡可能減少語句的logical reads。? ?
?
這里說的logical reads是指語句執(zhí)行時需要訪問的單位為8K的數(shù)據(jù)頁總數(shù)。
logical reads 越少,其需要的內(nèi)存和CPU時間也就越少,語句執(zhí)行速度就越快。
不言而喻,索引的最大好處是它可以極大減少SQL語句的logical reads數(shù)目,從而極大減少語句的執(zhí)行時間。
創(chuàng)建索引的關(guān)鍵是索引要能夠大大減少語句的logical reads。一個索引好不好,主要看它減少的logical reads多不多。
?
運行set statistics io命令可以得到SQL語句的logical reads信息。
set?statistics?io?on select?au_id,au_lname?,au_fname? from?pubs..authors?where?au_lname?='Green' set?statistics?io?on
如果Logical reads很大,而返回的行數(shù)很少,也即兩者相差較大,那么往往意味者語句需要優(yōu)化。
Logical reads中包含該語句從內(nèi)存數(shù)據(jù)緩沖區(qū)中訪問的頁數(shù)和從物理磁盤讀取的頁數(shù)。
而physical reads表示那些沒有駐留在內(nèi)存緩沖區(qū)中需要從磁盤讀取的數(shù)據(jù)頁。
Read-ahead reads是SQL Server為了提高性能而產(chǎn)生的預(yù)讀。預(yù)讀可能會多讀取一些數(shù)據(jù)。?
優(yōu)化的時候我們主要關(guān)注Logical Reads就可以了。
注意如果physical Reads或Read-ahead reads很大,那么往往意味著語句的執(zhí)行時間(duration)里面會有一部分耗費在等待物理磁盤IO上。
二、單字段索引,組合索引和覆蓋索引 ?
單字段索引是指只有一個字段的索引,而組合索引指有多個字段構(gòu)成的索引。
1. 對出現(xiàn)在where子句中的字段加索引 ?
set?statistics?profile?on set?statistics?io?on go select?....?from?tb?where?... go set?statistics?profile?off set?statistics?io?off
set statistics profile命令將輸出語句的執(zhí)行計劃。
也許你會問,為什么不用SET SHOWPLAN_ALL呢?使用SET SHOWPLAN_ALL也是可以的。
不過set statistics profile輸出的是SQL 語句的運行時候真正使用的執(zhí)行計劃,
而SET SHOWPLAN_ALL輸出的是預(yù)計(Estimate)的執(zhí)行計劃。
使用SET SHOWPLAN_ALL是后面的語句并不會真正運行。
用了Table Scan,也就是對整個表進行了全表掃描。全表掃描的性能通常是很差的,要盡量避免。
如果上面的select語句是數(shù)據(jù)庫系統(tǒng)經(jīng)常運行的關(guān)鍵語句, 那么應(yīng)該對它創(chuàng)建相應(yīng)的索引。
創(chuàng)建索引的技巧之一是對經(jīng)常出現(xiàn)在where條件中的字段創(chuàng)建索引
Table Scan也變成了Index Seek,性能極大提高
設(shè)法避免Table scan或Index scan是優(yōu)化SQL 語句使用的常用技巧。通常Index Seek需要的logical reads比前兩者要少得多。
2.組合索引 ?
?
如果where語句中有多個字段,那么可以考慮創(chuàng)建組合索引。
組合索引中字段的順序是非常重要的,越是唯一的字段越是要靠前 ? ?。 ?
另外,無論是組合索引還是單個列的索引,盡量不要選擇那些唯一性很低的字段。
比如說,在只有兩個值0和1的字段上建立索引沒有多大意義。
所以如果對單字段進行索引,建議使用set statistics profile來驗證索引確實被充分使用。logical reads越少的索引越好。
3.覆蓋索引? ?
覆蓋索引能夠使得語句不需要訪問表僅僅訪問索引就能夠得到所有需要的數(shù)據(jù)。
因為聚集索引葉子節(jié)點就是數(shù)據(jù)所以無所謂覆蓋與否,所以覆蓋索引主要是針對非聚集索引而言。
執(zhí)行計劃中除了index seek外,還有一個Bookmark Lookup關(guān)鍵字。
?
Bookmark Lookup表示語句在訪問索引后還需要對表進行額外的Bookmark Lookup操作才能得到數(shù)據(jù)。
也就是說為得到一行數(shù)據(jù)起碼有兩次IO,一次訪問索引,一次訪問基本表。
如果語句返回的行數(shù)很多,那么Bookmark Lookup操作的開銷是很大的。
覆蓋索引能夠避免昂貴的Bookmark Lookup操作,減少IO的次數(shù),提高語句的性能。
覆蓋索引需要包含select子句和WHERE子句中出現(xiàn)的所有字段。Where語句中的字段在前面,select中的在后面。
logical reads,是大大減少了。Bookmark Lookup操作也消失了。所以創(chuàng)建覆蓋索引是減少logical reads提升語句性能的非常有用的優(yōu)化技巧。
創(chuàng)建原則: ? ?
實際上索引的創(chuàng)建原則是比較復(fù)雜的。有時候你無法在索引中包含了Where子句中所有的字段。 ?
在考慮索引是否應(yīng)該包含一個字段時,應(yīng)考慮該字段在語句中的作用。
比如說如果經(jīng)常以某個字段作為where條件作精確匹配返回很少的行,那么就絕對值得為這個字段建立索引。
再比如說,對那些非常唯一的字段如主鍵和外鍵,經(jīng)常出現(xiàn)在group by,order by中的字段等等都值得創(chuàng)建索引。
問題1,是否值得在identity字段上建立聚集索引。? ?
答案取決于identity 字段如何在語句中使用。如果你經(jīng)常根據(jù)該字段搜索返回很少的行,那么在其上建立索引是值得的。
反之如果identity字段根本很少在語句中使用,那么就不應(yīng)該對其建立任何索引。
問題2,一個表應(yīng)該建立多少索引合適。? ?
如果表的80%以上的語句都是讀操作,那么索引可以多些。但是不要太多。
特別是不要對那些更新頻繁的表其建立很多的索引。很少表有超過5個以上的索引。? ?
過多的索引不但增加其占用的磁盤空間,也增加了SQL Server 維護索引的開銷。
問題4:為什么SQL Server 在執(zhí)行計劃中沒有使用你認為應(yīng)該使用的索引?原因是多樣的。
一種原因是該語句返回的結(jié)果超過了表的20%數(shù)據(jù),使得SQL Server 認為scan比seek更有效。
?
另一種原因可能是表字段的statistics過期了,不能準確反映數(shù)據(jù)的分布情況。
你可以使用命令UPDATE STATISTICS tablename with FULLSCAN來更新它。
只有同步的準確的statistics才能保證SQL Server 產(chǎn)生正確的執(zhí)行計劃。
過時的老的statistics常會導(dǎo)致SQL Server生成不夠優(yōu)化的甚至愚蠢的執(zhí)行計劃。
所以如果你的表頻繁更新,而你又覺得和之相關(guān)的SQL語句運行緩慢,不妨試試UPDATE STATISTIC with FULLSCAN 語句。
問題5、什么使用聚集索引,什么時候使用非聚集索引 ?
?
在SQL Server 中索引有聚集索引和非聚集索引兩種。它們的主要差別是前者的索引葉子就是數(shù)據(jù)本身,而后者的葉子節(jié)點包含的是指向數(shù)據(jù)的書簽(即數(shù)據(jù)行號或聚集索引的key)。
?
對一個表而言聚集索引只能有一個,而非聚集索引可以有多個。
只是聚集索引沒有Bookmark Lookup操作。
?
什么時候應(yīng)該使用聚集索引? ?什么時候使用非聚集索引? 取決于應(yīng)用程序的訪問模式。
?
我的建議是在那些關(guān)鍵的字段上使用聚集索引。一個表一般都需要建立一個聚集索引。
?
對于什么時候使用聚集索引,SQL Server 2000聯(lián)機手冊中有如下描述:
?
在創(chuàng)建聚集索引之前,應(yīng)先了解您的數(shù)據(jù)是如何被訪問的。 ? ?可考慮將聚集索引用于: ?
?
包含大量非重復(fù)值的列。
?
使用下列運算符返回一個范圍值的查詢:BETWEEN、>、>=、
?
被連續(xù)訪問的列。
?
返回大型結(jié)果集的查詢。
?
經(jīng)常被使用聯(lián)接或 GROUP BY 子句的查詢訪問的列;一般來說,這些是外鍵列。
?
對 ORDER BY 或 GROUP BY 子句中指定的列進行索引,可以使 SQL Server 不必對數(shù)據(jù)進行排序,因為這些行已經(jīng)排序。這樣可以提高查詢性能。
?
OLTP 類型的應(yīng)用程序,這些程序要求進行非常快速的單行查找(一般通過主鍵)。應(yīng)在主鍵上創(chuàng)建聚集索引。
?
聚集索引不適用于:? ?
頻繁更改的列
?
這將導(dǎo)致整行移動(因為 SQL Server 必須按物理順序保留行中的數(shù)據(jù)值)。這一點要特別注意,因為在大數(shù)據(jù)量事務(wù)處理系統(tǒng)中數(shù)據(jù)是易失的。
?
寬鍵
??
來自聚集索引的鍵值由所有非聚集索引作為查找鍵使用,因此存儲在每個非聚集索引的葉條目內(nèi)。
?
總結(jié): ?
?
如何使一個性能緩慢的系統(tǒng)運行更快更高效,不但需要整體分析數(shù)據(jù)庫系統(tǒng),找出系統(tǒng)的性能瓶頸,更需要優(yōu)化數(shù)據(jù)庫系統(tǒng)發(fā)出的SQL 語句。
一旦找出關(guān)鍵的SQL 語句并加與優(yōu)化,性能問題就會迎刃而解。
?
?
?
?
?
?
《 數(shù)據(jù)庫技術(shù)內(nèi)幕 》
處理百萬級以上的數(shù)據(jù)提高查詢速度的方法:
?1.應(yīng)盡量避免在?where?子句中使用!=或操作符,否則將引擎放棄使用索引而進行全表掃描。
?2.對查詢進行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在?where?及?order?by?涉及的列上建立索引。
?3.應(yīng)盡量避免在?where?子句中對字段進行?null?值判斷,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,如:
?????select?id?from?t?where?num?is?null
?????可以在num上設(shè)置默認值0,確保表中num列沒有null值,然后這樣查詢:
?????select?id?from?t?where?num=0
?4.應(yīng)盡量避免在?where?子句中使用?or?來連接條件,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,如:
?????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.下面的查詢也將導(dǎo)致全表掃描:(不能前置百分號)
?????select?id?from?t?where?name?like?‘%abc%’
????若要提高效率,可以考慮全文檢索。
?6.in?和?not?in?也要慎用,否則會導(dǎo)致全表掃描,如:
?????select?id?from?t?where?num?in(1,2,3)
?????對于連續(xù)的數(shù)值,能用?between?就不要用?in?了:
?????select?id?from?t?where?num?between?1?and?3
select?xx,phone? ?FROM?send??a? ?JOIN?( ?
? ?select? ?‘ ?13891030091 ?‘?phone?? ?union? ?select? ?‘ ?13992085916 ?‘?…………?? ?UNION?? ?SELECT? ?‘ ?13619100234 ?‘?)?b? ?
?? ?on??a.Phone ?=b.phone ?
— ?替代下面??很多數(shù)據(jù)隔開的時候 ?
?in( ?‘ ?13891030091 ?‘, ?‘ ?13992085916 ?‘, ?‘ ?13619100234 ?‘…………)
?
7.如果在?where?子句中使用參數(shù),也會導(dǎo)致全表掃描。因為SQL只有在運行時才會解析局部變量,但優(yōu)化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然?而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
?????select?id?from?t?where?num=@num?????可以改為強制查詢使用索引:
?????select?id?from?t?with(index(索引名))?where?num=@num
?8.應(yīng)盡量避免在?where?子句中對字段進行表達式操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描。如:
?????select?id?from?t?where?num/2=100
?????應(yīng)改為:
?????select?id?from?t?where?num=100*2
?9.應(yīng)盡量避免在where子句中對字段進行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描。如:
?????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
?????應(yīng)改為:
?????select?id?from?t?where?name?like?‘a(chǎn)bc%’
?????select?id?from?t?where?createdate>=’2005–11–30′?and?createdate’2005–12–1′
?10.不要在?where?子句中的“=”左邊進行函數(shù)、算術(shù)運算或其他表達式運算,否則系統(tǒng)將可能無法正確使用索引。
?11.在使用索引字段作為條件時,如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,否則該索引將不會被使?用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
?12.不要寫一些沒有意義的查詢,如需要生成一個空表結(jié)構(gòu):
?????select?col1,col2?into?#t?from?t?where?1=0
?????這類代碼不會返回任何結(jié)果集,但是會消耗系統(tǒng)資源的,應(yīng)改成這樣:
?????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是根據(jù)表中數(shù)據(jù)來進行查詢優(yōu)化的,當索引列有大量數(shù)據(jù)重復(fù)時,SQL查詢可能不會去利用索引,如一表中有字段?sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。
?15.索引并不是越多越好,索引固然可以提高相應(yīng)的?select?的效率,但同時也降低了?insert?及?update?的效率,因為?insert?或?update?時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數(shù)最好不要超過6個,若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有?必要。
?16.應(yīng)盡可能的避免更新?clustered?索引數(shù)據(jù)列,因為?clustered?索引數(shù)據(jù)列的順序就是表記錄的物理存儲順序,一旦該列值改變將導(dǎo)致整個表記錄的順序的調(diào)整,會耗費相當大的資源。若應(yīng)用系統(tǒng)需要頻繁更新?clustered?索引數(shù)據(jù)列,那么需要考慮是否應(yīng)將該索引建為?clustered?索引。
?17.盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接時會?逐個比較字符串中每一個字符,而對于數(shù)字型而言只需要比較一次就夠了。
?18.盡可能的使用?varchar/nvarchar?代替?char/nchar?,因為首先變長字段存儲空間小,可以節(jié)省存儲空間,其次對于查詢來說,在一個相對較小的字段內(nèi)搜索效率顯然要高些。
?19.任何地方都不要使用?select?*?from?t?,用具體的字段列表代替“*”,不要返回用不到的任何字段。
?20.盡量使用表變量來代替臨時表。如果表變量包含大量數(shù)據(jù),請注意索引非常有限(只有主鍵索引)。
?21.避免頻繁創(chuàng)建和刪除臨時表,以減少系統(tǒng)表資源的消耗。
?22.臨時表并不是不可使用,適當?shù)厥褂盟鼈兛梢允鼓承├谈行В纾斝枰貜?fù)引用大型表或常用表中的某個數(shù)據(jù)集時。但是,對于一次性事件,最好使?用導(dǎo)出表。
?23.在新建臨時表時,如果一次性插入數(shù)據(jù)量很大,那么可以使用?select?into?代替?create?table,避免造成大量?log?,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create?table,然后insert。
?24.如果使用到了臨時表,在存儲過程的最后務(wù)必將所有的臨時表顯式刪除,先?truncate?table?,然后?drop?table?,這樣可以避免系統(tǒng)表的較長時間鎖定。
?25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數(shù)據(jù)超過1萬行,那么就應(yīng)該考慮改寫。
?26.使用基于游標的方法或臨時表方法之前,應(yīng)先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。
?27.與臨時表一樣,游標并不是不可使用。對小型數(shù)據(jù)集使用?FAST_FORWARD?游標通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數(shù)據(jù)時。在結(jié)果集中包括“合計”的例程通常要比使用游標執(zhí)行的速度快。如果開發(fā)時?間允許,基于游標的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
?28.在所有的存儲過程和觸發(fā)器的開始處設(shè)置?SET?NOCOUNT?ON?,在結(jié)束時設(shè)置?SET?NOCOUNT?OFF?。無需在執(zhí)行存儲過程和觸發(fā)器的每個語句后向客戶端發(fā)送?DONE_IN_PROC?消息。
?29.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應(yīng)該考慮相應(yīng)需求是否合理。
?30.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。
查詢速度慢的原因:
1、沒有索引或者沒有用到索引(這是查詢慢最常見的問題,是程序設(shè)計的缺陷)?
?
2、I/O吞吐量小,形成了瓶頸效應(yīng)。??
3、沒有創(chuàng)建計算列導(dǎo)致查詢不優(yōu)化。?
?
4、內(nèi)存不足??
5、網(wǎng)絡(luò)速度慢??
6、查詢出的數(shù)據(jù)量過大(可以采用多次查詢,其他的方法降低數(shù)據(jù)量)??
7、鎖或者死鎖(這也是查詢慢最常見的問題,是程序設(shè)計的缺陷)??
8、sp_lock,sp_who,活動的用戶查看,原因是讀寫競爭資源。
??
9、返回了不必要的行和列??
10、查詢語句不好,沒有優(yōu)化??
可以通過如下方法來優(yōu)化查詢??
1、把數(shù)據(jù)、日志、索引放到不同的I/O設(shè)備上,增加讀取速度,以前可以將Tempdb應(yīng)放在RAID0上,SQL2000不在支持。數(shù)據(jù)量(尺寸)越大,提高I/O越重要.??
2、縱向、橫向分割表,減少表的尺寸(sp_spaceuse)??
3、升級硬件??
4、根據(jù)查詢條件,建立索引,優(yōu)化索引、優(yōu)化訪問方式,限制結(jié)果集的數(shù)據(jù)量。注意填充因子要適當(最好是使用默認值0)。索引應(yīng)該盡量小,使用字節(jié)數(shù)小的列建索引好(參照索引的創(chuàng)建),不要對有限的幾個值的字段建單一索引如性別字段??
5、提高網(wǎng)速;??
6、擴大服務(wù)器的內(nèi)存,Windows???2000和SQL???server???2000能支持4–8G的內(nèi)存。配置虛擬內(nèi)存:虛擬內(nèi)存大小應(yīng)基于計算機上并發(fā)運行的服務(wù)進行配置。運行???Microsoft???SQL???Server????2000???時,可考慮將虛擬內(nèi)存大小設(shè)置為計算機中安裝的物理內(nèi)存的???1.5???倍。如果另外安裝了全文檢索功能,并打算運行???Microsoft???搜索服務(wù)以便執(zhí)行全文索引和查詢,可考慮:將虛擬內(nèi)存大小配置為至少是計算機中安裝的物理內(nèi)存的???3???倍。將???SQL???Server???max???server???memory???服務(wù)器配置選項配置為物理內(nèi)存的???1.5???倍(虛擬內(nèi)存大小設(shè)置的一半)。??
7、增加服務(wù)器CPU個數(shù);但是必須明白并行處理串行處理更需要資源例如內(nèi)存。使用并行還是串行程是MsSQL自動評估選擇的。單個任務(wù)分解成多個任務(wù),就可以在處理器上運行。例如耽擱查詢的排序、連接、掃描和GROUP???BY字句同時執(zhí)行,SQL???SERVER根據(jù)系統(tǒng)的負載情況決定最優(yōu)的并行等級,復(fù)雜的需要消耗大量的CPU的查詢最適合并行處理。但是更新操作UPDATE,INSERT,?DELETE還不能并行處理。??
8、如果是使用like進行查詢的話,簡單的使用index是不行的,但是全文索引,耗空間。???like???‘a%‘???使用索引???like???‘%a‘???不使用索引用???like???‘%a%‘???查詢時,查詢耗時和字段值總長度成正比,所以不能用CHAR類型,而是VARCHAR。對于字段的值很長的建全文索引。??
9、DB???Server???和APPLication???Server???分離;OLTP和OLAP分離??
10、分布式分區(qū)視圖可用于實現(xiàn)數(shù)據(jù)庫服務(wù)器聯(lián)合體。聯(lián)合體是一組分開管理的服務(wù)器,但它們相互協(xié)作分擔(dān)系統(tǒng)的處理負荷。這種通過分區(qū)數(shù)據(jù)形成數(shù)據(jù)庫服務(wù)器聯(lián)合體的機制能夠擴大一組服務(wù)器,以支持大型的多層???Web???站點的處理需要。有關(guān)更多信息,參見設(shè)計聯(lián)合數(shù)據(jù)庫服務(wù)器。(參照SQL幫助文件‘分區(qū)視圖‘)??
????a、在實現(xiàn)分區(qū)視圖之前,必須先水平分區(qū)表??
????b、在創(chuàng)建成員表后,在每個成員服務(wù)器上定義一個分布式分區(qū)視圖,并且每個視圖具有相同的名稱。這樣,引用分布式分區(qū)視圖名的查詢可以在任何一個成員服務(wù)器上運行。系統(tǒng)操作如同每個成員服務(wù)器上都有一個原始表的復(fù)本一樣,但其實每個服務(wù)器上只有一個成員表和一個分布式分區(qū)視圖。數(shù)據(jù)的位置對應(yīng)用程序是透明的。??
11、重建索引???DBCC???REINDEX???,DBCC???INDEXDEFRAG,收縮數(shù)據(jù)和日志???DBCC???SHRINKDB,DBCC???SHRINKFILE.???設(shè)置自動收縮日志.對于大的數(shù)據(jù)庫不要設(shè)置數(shù)據(jù)庫自動增長,它會降低服務(wù)器的性能。???在T–sql的寫法上有很大的講究,下面列出常見的要點:首先,DBMS處理查詢計劃的過程是這樣的:??
????1、???查詢語句的詞法、語法檢查??????????
????2、???將語句提交給DBMS的查詢優(yōu)化器??
????3、???優(yōu)化器做代數(shù)優(yōu)化和存取路徑的優(yōu)化??
????4、???由預(yù)編譯模塊生成查詢規(guī)劃??
????5、???然后在合適的時間提交給系統(tǒng)處理執(zhí)行??
????6、???最后將執(zhí)行結(jié)果返回給用戶其次,看一下SQL???SERVER的數(shù)據(jù)存放的結(jié)構(gòu):一個頁面的大小為8K(8060)字節(jié),8個頁面為一個盤區(qū),按照B樹存放。??
12、Commit和rollback的區(qū)別???Rollback:回滾所有的事物。???Commit:提交當前的事物.???沒有必要在動態(tài)SQL里寫事物,如果要寫請寫在外面如:???begin???tran???exec(@s)???commit???trans???或者將動態(tài)SQL???寫成函數(shù)或者存儲過程。??
13、在查詢Select語句中用Where字句限制返回的行數(shù),避免表掃描,如果返回不必要的數(shù)據(jù),浪費了服務(wù)器的I/O資源,加重了網(wǎng)絡(luò)的負擔(dān)降低性能。如果表很大,在表掃描的期間將表鎖住,禁止其他的聯(lián)接訪問表,后果嚴重。??
14、SQL的注釋申明對執(zhí)行沒有任何影響??
15、盡可能不使用游標,它占用大量的資源。如果需要row–by–row地執(zhí)行,盡量采用非光標技術(shù),如:在客戶端循環(huán),用臨時表,Table變量,用子查詢,用Case語句等等。游標可以按照它所支持的提取選項進行分類:???只進???必須按照從第一行到最后一行的順序提取行。FETCH???NEXT???是唯一允許的提取操作,也是默認方式。可滾動性???可以在游標中任何地方隨機提取任意行。游標的技術(shù)在SQL2000下變得功能很強大,他的目的是支持循環(huán)。??
有四個并發(fā)選項??
READ_ONLY:不允許通過游標定位更新(Update),且在組成結(jié)果集的行中沒有鎖。??
OPTIMISTIC???WITH???valueS:樂觀并發(fā)控制是事務(wù)控制理論的一個標準部分。樂觀并發(fā)控制用于這樣的情形,即在打開游標及更新行的間隔中,只有很小的機會讓第二個用戶更新某一行。當某個游標以此選項打開時,沒有鎖控制其中的行,這將有助于最大化其處理能力。如果用戶試圖修改某一行,則此行的當前值會與最后一次提取此行時獲取的值進行比較。如果任何值發(fā)生改變,則服務(wù)器就會知道其他人已更新了此行,并會返回一個錯誤。如果值是一樣的,服務(wù)器就執(zhí)行修改。???選擇這個并發(fā)選項OPTIMISTIC???WITH???ROW???VERSIONING:此樂觀并發(fā)控制選項基于行版本控制。使用行版本控制,其中的表必須具有某種版本標識符,服務(wù)器可用它來確定該行在讀入游標后是否有所更改。??
在???SQL???Server???中,這個性能由???timestamp???數(shù)據(jù)類型提供,它是一個二進制數(shù)字,表示數(shù)據(jù)庫中更改的相對順序。每個數(shù)據(jù)庫都有一個全局當前時間戳值:@@DBTS。每次以任何方式更改帶有???timestamp???列的行時,SQL???Server???先在時間戳列中存儲當前的???@@DBTS???值,然后增加???@@DBTS???的值。如果某???個表具有???timestamp???列,則時間戳?xí)挥浀叫屑墶7?wù)器就可以比較某行的當前時間戳值和上次提取時所存儲的時間戳值,從而確定該行是否已更新。服務(wù)器不必比較所有列的值,只需比較???timestamp???列即可。如果應(yīng)用程序?qū)]有???timestamp???列的表要求基于行版本控制的樂觀并發(fā),則游標默認為基于數(shù)值的樂觀并發(fā)控制。??
SCROLL???LOCKS???這個選項實現(xiàn)悲觀并發(fā)控制。在悲觀并發(fā)控制中,在把數(shù)據(jù)庫的行讀入游標結(jié)果集時,應(yīng)用程序?qū)⒃噲D鎖定數(shù)據(jù)庫行。在使用服務(wù)器游標時,將行讀入游標時會在其上放置一個更新鎖。如果在事務(wù)內(nèi)打開游標,則該事務(wù)更新鎖將一直保持到事務(wù)被提交或回滾;當提取下一行時,將除去游標鎖。如果在事務(wù)外打開游標,則提取下一行時,鎖就被丟棄。因此,每當用戶需要完全的悲觀并發(fā)控制時,游標都應(yīng)在事務(wù)內(nèi)打開。更新鎖將阻止任何其它任務(wù)獲取更新鎖或排它鎖,從而阻止其它任務(wù)更新該行。??
然而,更新鎖并不阻止共享鎖,所以它不會阻止其它任務(wù)讀取行,除非第二個任務(wù)也在要求帶更新鎖的讀取。滾動鎖根據(jù)在游標定義的???SELECT???語句中指定的鎖提示,這些游標并發(fā)選項可以生成滾動鎖。滾動鎖在提取時在每行上獲取,并保持到下次提取或者游標關(guān)閉,以先發(fā)生者為準。下次提取時,服務(wù)器為新提取中的行獲取滾動鎖,并釋放上次提取中行的滾動鎖。滾動鎖獨立于事務(wù)鎖,并可以保持到一個提交或回滾操作之后。如果提交時關(guān)閉游標的選項為關(guān),則???COMMIT???語句并不關(guān)閉任何打開的游標,而且滾動鎖被保留到提交之后,以維護對所提取數(shù)據(jù)的隔離。所獲取滾動鎖的類型取決于游標并發(fā)選項和游標???SELECT???語句中的鎖提示。??
鎖提示???只讀???樂觀數(shù)值???樂觀行版本控制???鎖定無提示???未鎖定???未鎖定???未鎖定???更新???NOLOCK???未鎖定???未鎖定???未鎖定???未鎖定???HOLDLOCK???共享???共享???共享???更新???UPDLOCK???錯誤???更新???更新???更新???TABLOCKX???錯誤???未鎖定???未鎖定???更新其它???未鎖定???未鎖定???未鎖定???更新???*指定???NOLOCK???提示將使指定了該提示的表在游標內(nèi)是只讀的。??
16、用Profiler來跟蹤查詢,得到查詢所需的時間,找出SQL的問題所在;用索引優(yōu)化器優(yōu)化索引??
17、注意UNion和UNion???all???的區(qū)別。UNION???all好??
18、注意使用DISTINCT,在沒有必要時不要用,它同UNION一樣會使查詢變慢。重復(fù)的記錄在查詢里是沒有問題的??
19、查詢時不要返回不需要的行、列??
20、用sp_configure???‘query???governor???cost???limit‘或者SET???QUERY_GOVERNOR_COST_LIMIT來限制查詢消耗的資源。當評估查詢消耗的資源超出限制時,服務(wù)器自動取消查詢,在查詢之前就扼殺掉。?SET???LOCKTIME設(shè)置鎖的時間??
21、用select???top???100???/???10???Percent???來限制用戶返回的行數(shù)或者SET???ROWCOUNT來限制操作的行??
22、在SQL2000以前,一般不要用如下的字句?“IS???NULL“,???”??“,???“!=“,???“!>?“,???“!?“,???“NOT“,???“NOT???EXISTS“,???“NOT???IN“,???“NOT???LIKE“,???and???“LIKE???‘%500‘“,因為他們不走索引全是表掃描。
也不要在WHere字句中的列名加函數(shù),如Convert,substring等,如果必須用函數(shù)的時候,創(chuàng)建計算列再創(chuàng)建索引來替代.還可以變通寫法:WHERE???SUBSTRING(firstname,1,1)???=???‘m‘改為WHERE???firstname???like???‘m%‘(索引掃描),一定要將函數(shù)和列名分開。并且索引不能建得太多和太大。
NOT???IN會多次掃描表,使用EXISTS、NOT???EXISTS???,IN???,???LEFT???OUTER???JOIN???來替代,特別是左連接,而Exists比IN更快,最慢的是NOT操作.如果列的值含有空,以前它的索引不起作用,現(xiàn)在2000的優(yōu)化器能夠處理了。相同的是IS???NULL,“NOT“,???“NOT???EXISTS“,???“NOT???IN“能優(yōu)化她,而”??”等還是不能優(yōu)化,用不到索引。??
23、使用Query???Analyzer,查看SQL語句的查詢計劃和評估分析是否是優(yōu)化的SQL。一般的20%的代碼占據(jù)了80%的資源,我們優(yōu)化的重點是這些慢的地方。??
24、如果使用了IN或者OR等時發(fā)現(xiàn)查詢沒有走索引,使用顯示申明指定索引:???SELECT???*???FROM???PersonMember???(INDEX???=???IX_Title)???WHERE???processid???IN???(‘男’,‘女’)??
25、將需要查詢的結(jié)果預(yù)先計算好放在表中,查詢的時候再SELECT。這在SQL7.0以前是最重要的手段。例如醫(yī)院的住院費計算。??
26、MIN()???和???MAX()能使用到合適的索引??
27、數(shù)據(jù)庫有一個原則是代碼離數(shù)據(jù)越近越好,所以優(yōu)先選擇Default,依次為Rules,Triggers,???Constraint(約束如外健主健CheckUNIQUE……,數(shù)據(jù)類型的最大長度等等都是約束),Procedure.這樣不僅維護工作小,編寫程序質(zhì)量高,并且執(zhí)行的速度快。??
28、如果要插入大的二進制值到Image列,使用存儲過程,千萬不要用內(nèi)嵌INsert來插入(不知Java是否)。因為這樣應(yīng)用程序首先將二進制值轉(zhuǎn)換成字符串(尺寸是它的兩倍),服務(wù)器受到字符后又將他轉(zhuǎn)換成二進制值.存儲過程就沒有這些動作:???方法:Create???procedure???p_insert???as???insert???into???table(Fimage)???values???(@image),???在前臺調(diào)用這個存儲過程傳入二進制參數(shù),這樣處理速度明顯改善。??
29、Between在某些時候比IN速度更快,Between能夠更快地根據(jù)索引找到范圍。用查詢優(yōu)化器可見到差別。???select???*???from???chineseresume???where???title???in???(‘男‘,‘女‘)???Select???*???from???chineseresume???where???between???‘男‘???and???‘女‘???是一樣的。由于in會在比較多次,所以有時會慢些。??
30、在必要是對全局或者局部臨時表創(chuàng)建索引,有時能夠提高速度,但不是一定會這樣,因為索引也耗費大量的資源。他的創(chuàng)建同是實際表一樣。??
31、不要建沒有作用的事物例如產(chǎn)生報表時,浪費資源。只有在必要使用事物時使用它。??
32、用OR的字句可以分解成多個查詢,并且通過UNION???連接多個查詢。他們的速度只同是否使用索引有關(guān),如果查詢需要用到聯(lián)合索引,用UNION???all執(zhí)行的效率更高.多個OR的字句沒有用到索引,改寫成UNION的形式再試圖與索引匹配。一個關(guān)鍵的問題是否用到索引。??
33、盡量少用視圖,它的效率低。對視圖操作比直接對表操作慢,可以用stored???procedure來代替她。特別的是不要用視圖嵌套,嵌套視圖增加了尋找原始資料的難度。我們看視圖的本質(zhì):它是存放在服務(wù)器上的被優(yōu)化好了的已經(jīng)產(chǎn)生了查詢規(guī)劃的SQL。對單個表檢索數(shù)據(jù)時,不要使用指向多個表的視圖,直接從表檢索或者僅僅包含這個表的視圖上讀,否則增加了不必要的開銷,查詢受到干擾.為了加快視圖的查詢,MsSQL增加了視圖索引的功能。??
34、沒有必要時不要用DISTINCT和ORDER???BY,這些動作可以改在客戶端執(zhí)行。它們增加了額外的開銷。這同UNION???和UNION???ALL一樣的道理。???SELECT???top???20???ad.companyname,comid,position,ad.referenceid,worklocation,???convert(varchar(10),ad.postDate,120)???as???postDate1,workyear,degreedescription???FROM???jobcn_query.dbo.COMPANYAD_query???ad???where???referenceID???in(‘JCNAD00329667‘,‘JCNAD132168‘,‘JCNAD00337748‘,‘JCNAD00338345‘,‘JCNAD00333138‘,‘JCNAD00303570‘,???‘JCNAD00303569‘,‘JCNAD00303568‘,‘JCNAD00306698‘,‘JCNAD00231935‘,‘JCNAD00231933‘,‘JCNAD00254567‘,???‘JCNAD00254585‘,‘JCNAD00254608‘,‘JCNAD00254607‘,‘JCNAD00258524‘,‘JCNAD00332133‘,‘JCNAD00268618‘,???‘JCNAD00279196‘,‘JCNAD00268613‘)???order???by???postdate???desc??
35、在IN后面值的列表中,將出現(xiàn)最頻繁的值放在最前面,出現(xiàn)得最少的放在最后面,減少判斷的次數(shù)??
36、當用SELECT???INTO時,它會鎖住系統(tǒng)表(sysobjects,sysindexes等等),阻塞其他的連接的存取。創(chuàng)建臨時表時用顯示申明語句,而不是?select???INTO.???drop???table???t_lxh???begin???tran???select???*???into???t_lxh???from???chineseresume???where???name???=???‘XYZ‘???—commit???在另一個連接中SELECT???*???from???sysobjects可以看到???SELECT???INTO???會鎖住系統(tǒng)表,Create???table???也會鎖系統(tǒng)表(不管是臨時表還是系統(tǒng)表)。所以千萬不要在事物內(nèi)使用它!!!這樣的話如果是經(jīng)常要用的臨時表請使用實表,或者臨時表變量。??
37、一般在GROUP???BY???個HAVING字句之前就能剔除多余的行,所以盡量不要用它們來做剔除行的工作。他們的執(zhí)行順序應(yīng)該如下最優(yōu):select???的Where字句選擇所有合適的行,Group???By用來分組個統(tǒng)計行,Having字句用來剔除多余的分組。這樣Group???By???個Having的開銷小,查詢快.對于大的數(shù)據(jù)行進行分組和Having十分消耗資源。如果Group???BY的目的不包括計算,只是分組,那么用Distinct更快??
38、一次更新多條記錄比分多次更新每次一條快,就是說批處理好??
39、少用臨時表,盡量用結(jié)果集和Table類性的變量來代替它,Table???類型的變量比臨時表好??
40、在SQL2000下,計算字段是可以索引的,需要滿足的條件如下:??
??a、計算字段的表達是確定的??
??b、不能用在TEXT,Ntext,Image數(shù)據(jù)類型??
??c、必須配制如下選項???ANSI_NULLS???=???ON,???ANSI_PADDINGS???=???ON,???…….??
41、盡量將數(shù)據(jù)的處理工作放在服務(wù)器上,減少網(wǎng)絡(luò)的開銷,如使用存儲過程。存儲過程是編譯好、優(yōu)化過、并且被組織到一個執(zhí)行規(guī)劃里、且存儲在數(shù)據(jù)庫中的?SQL語句,是控制流語言的集合,速度當然快。反復(fù)執(zhí)行的動態(tài)SQL,可以使用臨時存儲過程,該過程(臨時表)被放在Tempdb中。以前由于SQL???SERVER對復(fù)雜的數(shù)學(xué)計算不支持,所以不得不將這個工作放在其他的層上而增加網(wǎng)絡(luò)的開銷。SQL2000支持UDFs,現(xiàn)在支持復(fù)雜的數(shù)學(xué)計算,函數(shù)的返回值不要太大,這樣的開銷很大。用戶自定義函數(shù)象光標一樣執(zhí)行的消耗大量的資源,如果返回大的結(jié)果采用存儲過程??
42、不要在一句話里再三的使用相同的函數(shù),浪費資源,將結(jié)果放在變量里再調(diào)用更快??
43、SELECT???COUNT(*)的效率教低,盡量變通他的寫法,而EXISTS快.同時請注意區(qū)別:???select???count(Field???of???null)???from???Table???和???select???count(Field???of???NOT???null)???from???Table???的返回值是不同的。??
44、當服務(wù)器的內(nèi)存夠多時,配制線程數(shù)量???=???最大連接數(shù)+5,這樣能發(fā)揮最大的效率;否則使用???配制線程數(shù)量?最大連接數(shù)啟用SQL???SERVER的線程池來解決,如果還是數(shù)量???=???最大連接數(shù)+5,嚴重的損害服務(wù)器的性能。??
45、按照一定的次序來訪問你的表。如果你先鎖住表A,再鎖住表B,那么在所有的存儲過程中都要按照這個順序來鎖定它們。如果你(不經(jīng)意的)某個存儲過程中先鎖定表B,再鎖定表A,這可能就會導(dǎo)致一個死鎖。如果鎖定順序沒有被預(yù)先詳細的設(shè)計好,死鎖很難被發(fā)現(xiàn)??
46、通過SQL???Server???Performance???Monitor監(jiān)視相應(yīng)硬件的負載???Memory:???Page???Faults???/???sec計數(shù)器如果該值偶爾走高,表明當時有線程競爭內(nèi)存。如果持續(xù)很高,則內(nèi)存可能是瓶頸。???Process:??
????1、%???DPC???Time???指在范例間隔期間處理器用在緩延程序調(diào)用(DPC)接收和提供服務(wù)的百分比。(DPC???正在運行的為比標準間隔優(yōu)先權(quán)低的間隔)。???由于???DPC???是以特權(quán)模式執(zhí)行的,DPC???時間的百分比為特權(quán)時間???百分比的一部分。這些時間單獨計算并且不屬于間隔計算總數(shù)的一部???分。這個總數(shù)顯示了作為實例時間百分比的平均忙時。??
????2、%Processor???Time計數(shù)器 如果該參數(shù)值持續(xù)超過95%,表明瓶頸是CPU。可以考慮增加一個處理器或換一個更快的處理器。??
????3、%???Privileged???Time???指非閑置處理器時間用于特權(quán)模式的百分比。(特權(quán)模式是為操作系統(tǒng)組件和操縱硬件驅(qū)動程序而設(shè)計的一種處理模式。它允許直接訪問硬件和所有內(nèi)存。另一種模式為用戶模式,它是一種為應(yīng)用程序、環(huán)境分系統(tǒng)和整數(shù)分系統(tǒng)設(shè)計的一種有限處理模式。操作系統(tǒng)將應(yīng)用程序線程轉(zhuǎn)換成特權(quán)模式以訪問操作系統(tǒng)服務(wù))。???特權(quán)時間的???%???包括為間斷和???DPC???提供服務(wù)的時間。特權(quán)時間比率高可能是由于失敗設(shè)備產(chǎn)生的大數(shù)量的間隔而引起的。這個計數(shù)器將平均忙時作為樣本時間的一部分顯示。??
????4、%???User???Time表示耗費CPU的數(shù)據(jù)庫操作,如排序,執(zhí)行aggregate???functions等。如果該值很高,可考慮增加索引,盡量使用簡單的表聯(lián)接,水平分割大表格等方法來降低該值。???Physical???Disk:???Curretn???Disk???Queue???Length計數(shù)器該值應(yīng)不超過磁盤數(shù)的1.5~2倍。要提高性能,可增加磁盤。???SQLServer:Cache???Hit???Ratio計數(shù)器該值越高越好。如果持續(xù)低于80%,應(yīng)考慮增加內(nèi)存。???注意該參數(shù)值是從SQL???Server啟動后,就一直累加記數(shù),所以運行經(jīng)過一段時間后,該值將不能反映系統(tǒng)當前值。??
47、分析select???emp_name???form???employee???where???salary???>???3000???在此語句中若salary是Float類型的,則優(yōu)化器對其進行優(yōu)化為Convert(float,3000),因為3000是個整數(shù),我們應(yīng)在編程時使用3000.0而不要等運行時讓DBMS進行轉(zhuǎn)化。同樣字符和整型數(shù)據(jù)的轉(zhuǎn)換。