




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
數(shù)據(jù)庫性能概要規(guī)范
N
DocumentInformation
LastUpdated6/6/21
Filename:數(shù)據(jù)庫性能概要規(guī)范.doc
AuthorInformation
AuthorDavidDong
GroupMIS
目錄
1目的..........................................................................5
2PerformanceAuditChecklist...............................................................5
3常用的數(shù)據(jù)庫優(yōu)化工具.........................................................6
4性能調(diào)整......................................................................6
4.1TSQL...........................................................................................6
4.1.1不要訪問多于你需要的數(shù)據(jù).......................................6
4.1.2所有者.對象名(objectownername.objectname)...............6
4.1.3Union&UnionAll...............................................................6
4.1.4Union&Jion......................................................................8
4.1.5Distinct..............................................................................9
4.1.6TOPN...............................................................................10
4.1.7InAndExist.....................................................................11
4.1.8InandBetween...............................................................11
4.1.9Like...................................................................................11
4.1.10OR....................................................................................12
4.1.11Orderby/sorting............................................................12
4.1.12Existandcount(*)...........................................................13
4.1.13使用Case...........................................................................14
4.1.14NullVsNotNull.................................................................15
4.1.15Bit.....................................................................................15
4.1.16字符串操作.....................................................15
4.1.17在Where語句中存在冗余條件..................................15
4.1.18在WHERE子句中的列上使用函數(shù)..............................16
4.1.19避免在WHERE中使用no-sargable....................................16
4.1.20避免使用游標(biāo)...................................................17
4.1.21使用存儲過程...................................................24
4.1.22不要包括不做任何事情的代碼....................................25
4.1.23sp_?.................................................................................25
4.1.24CHECKSUM索引..............................................25
4.1.25索引提示(Indexhint)......................................................26
4.2事務(wù)和死鎖............................................................26
4.2.1Transaction......................................................................27
4.2.2Complextransaction........................................................28
4.2.3Deadlock...........................................................................28
4.3表操作................................................................30
4.3.1AvoidTablescan..............................................................30
4.3.2SELECTINTO....................................................................30
4.3.3Update..............................................................................30
4.3.4大批量更新,刪除,插入數(shù)據(jù)....................................31
4.3.5TempTable&DerivedTables..........................................31
4.3.6有效的使用JOIN..................................................................34
4.3.7父子表..........................................................35
4.3.8關(guān)于統(tǒng)計(jì)信息(Statistics)...................................................35
4.3.9為列選擇合適數(shù)據(jù)類型...........................................36
5參考資料.....................................................................36
1目的
通過對?些常見的影響數(shù)據(jù)庫性能的查詢部分進(jìn)行分析,提出相應(yīng)的解決方法,以提高公司業(yè)務(wù)
數(shù)據(jù)庫業(yè)務(wù)系統(tǒng)的高可用性及可并發(fā)性。
本文基本分為兩部分,第一部分會給出一個簡單的checklst,列出了常見的一些影響性能的問
題,第二部分則強(qiáng)調(diào)在設(shè)計(jì),開發(fā)方面的性能調(diào)整問題。
另外,由于個人經(jīng)驗(yàn)的關(guān)系,本文檔可能會有很多的缺陷,如果各位能夠提供相關(guān)不足,將非常
感激,請發(fā)送郵件至DavidDonq@
說明:
在不同的數(shù)據(jù)庫環(huán)境中,相同的數(shù)據(jù)庫性能設(shè)置技巧可能會有完全不同的表現(xiàn)結(jié)果,所以性能方
面的技巧一般都是與特定的環(huán)境相關(guān)的,不能盲目的相信所謂的性能調(diào)整技巧,而在我們每次進(jìn)
行相關(guān)性能調(diào)整的過程中,我們也需要進(jìn)行多種測試來達(dá)到最理想的效果。
2PerformanceAuditChecklist
Transact-SQLChecklistYourCheck
查詢時(shí)不返回多余的數(shù)據(jù)(比如沒有SELECT*)
盡量不使用游標(biāo)
如果確實(shí)需要使用游標(biāo),能否有其他的解決方法
注意T-SQL語句中UNION和UNIONALL區(qū)別
盡量避免使用SELECTDISTINCT
注意T-SQL語句中Exist。和Count(*)區(qū)別
注意T-SQL語句中IN和EXISTS區(qū)別
在Where語句中不存在no-sargable("ISNULL",
n
"!>"z"NOTz"NOTIN","NOTLIKE';和"LIKE
'%500'")
注意在WHERE子句中不存在數(shù)據(jù)類型的轉(zhuǎn)換
注意在WHERE語句中不存在對列進(jìn)行函數(shù)操作
注意查詢中盡力避免使用臨時(shí)表
注意到臨時(shí)表不可由derivedtable替代
注意到查詢使用了合適的表提示
注意到?jīng)]有以sp_作為前綴的存儲過程
注意到存儲過程中是否使用了SETNOCOUNTON
注意到所有的數(shù)據(jù)庫對象是依dbo.objectname的形式來引用
盡力保證事務(wù)盡可能短小并盡可能不使用嵌套事務(wù)
對JOIN操作進(jìn)行了優(yōu)化
3常用的數(shù)據(jù)庫優(yōu)化工具
>QueryAnalyzer
>Profiler
>IndexWizard
>System(Performance)Monitor
4性能調(diào)整
以下分別從TSQL、事務(wù)和死鎖、表操作這三個方面來講性能調(diào)整的問題。
4.1TSQL
4.1.1不要訪問多于你需要的數(shù)據(jù)
這個聽起來是多余的,但是確實(shí)是非常必要的,做起來也不大容易。其中包括不要返回給客戶端
不需要的列和行。比如在SELECT語句中不要使用SELECT*,否則會經(jīng)常返回給客氣端多于
它們所需要的數(shù)據(jù),這樣可以有效減輕網(wǎng)絡(luò)傳輸壓力,減少不必要的I/O,以及減少內(nèi)存耗費(fèi),
并能夠使查詢優(yōu)化器最優(yōu)化我們的查詢執(zhí)行計(jì)劃,從而減少潛在的性能問題。
4.1.2所有者?對象名(objectownername.objectname)
建議在所有對表、視圖和存儲過程引用時(shí),加上它們的前綴。下面討論一下為什么使用前綴可以
改進(jìn)查詢性能。
例子:有一存儲過程dbo.foo,此存儲過程運(yùn)行查詢
SELECTcollFROMtablel
當(dāng)用戶Lucy調(diào)用存儲過程時(shí),查詢優(yōu)化器必須決定是檢索Lucy.tablel還是檢索dbo.tablelo
然后,當(dāng)用戶Lily調(diào)用同一個存儲過程時(shí),查詢優(yōu)化器必須對查詢計(jì)劃進(jìn)行重新編譯,以決定
用戶是需要Lily.tablel還是需要dbo.tablelo但是如果把上面的SELECT語句修改如下
SELECTcollFROMdbo.tablel
查詢優(yōu)化器將不會遇到任何模糊性,從而避免重新編譯,達(dá)到提升性能的目的。
4.1.3Union&UnionAll
首先講一下UNION的工作原理,當(dāng)使用UNION語句時(shí),它的功能與在結(jié)果集上SELECT
DISTINCT類似,也就是說使用UNION時(shí)它會首先合并兩個結(jié)果集,然后執(zhí)行一個類似于
SELECTDISTINCT的操作,以避免重復(fù)行的出現(xiàn)。這個過程在兩上結(jié)果集沒有任何重復(fù)行的
情況下也會進(jìn)行DISTINCT處理,所以如果我們確認(rèn)在UNION的兩個結(jié)果集確實(shí)存在重復(fù)行,
并且要消除重復(fù)行的出現(xiàn)時(shí),就可以使用UNION.從另一方面來說,如果我們知道在結(jié)果集中并
不會存在重復(fù)行,或者說出現(xiàn)重復(fù)行對我們的應(yīng)用程序沒有什么影響時(shí),我們應(yīng)該使用UNION
ALL語句來替代UNION語句,UNIONALL和UNION相比的優(yōu)點(diǎn)在于它并不會對兩個結(jié)果集
進(jìn)行SELECTDISTINCT操作,這樣可以節(jié)省SQLServer的資源使用。
例子:比較UNION和UNIONALL的差別:
--query1,useUnionAll,thesecondresultwillspendtothefirstresultset.
SELECT1,2
SELECT1,2
--query2zuseunion,thiswilldothedistinctoperation
SELECT1,2
SELECT1,2
我們來看一下其結(jié)果集,兀以在第一個查詢中只是把第二個查詢的結(jié)果集附加到第一個結(jié)果集
中,而第二個杳詢就執(zhí)行了DISTINCT操作,消除了重復(fù)行:
口Results_jMessages屋Executionplan
(Nocolumnname)(Nocolumnname)
(Nocolumnname)(Nocolumnname)
1i'1.........................■2
卜面來看性能方面的對比,分析卜.面的執(zhí)行計(jì)劃,我們可以看到第二個操作非常消耗資源,如果
兩個查詢一塊執(zhí)行時(shí),第二個查詢幾乎使用了所有的數(shù)據(jù)庫資源(主要消耗在MERGEJOIN中
的消除重復(fù)行部分):
Query1:Querycost(relativetothebatch):0%
select1,2unionallselect1,2
宣■一由
SELECTConcatenationConstantScan
Cost:0%Cost:IS%Cost:43%
ConstantScan
Query2:Querycost(relativetothebatch):100%
select1,2unionselect1,2
口大
MergeJoin;Tl
SELECTConstantScan
(Union)
Cost:0%Cost:0%
Cost:LOO+
_±1
ConstantScan
Cost:0%
結(jié)論:在對UNION和UNIONALL進(jìn)行選擇時(shí),除非必要,推薦使用UNIONALL
4.1.4Union&Jion
在比較UNION和UNIONALL的基礎(chǔ)上,下面來看UNION合并結(jié)果集和使用JION查詢得到
結(jié)果集之間的差別.
例子:使用UNION來合并多個結(jié)果集的情況:
USEPUBS;
GO
SELECTFROMDBO.SALES
WHEREQTY-.10
UNION
SELECTFROMDBO.SALES
WHEREQTY>11
上面的查詢可以被重寫為下面的查詢,這樣一般就會有性能提升:
USEPUBS;
GO
SELECTdistinctFROMDBO.SALES
WHEREQTY<10CxQTY>11
NOTE:如果知道結(jié)果集中并不存在重復(fù)的數(shù)據(jù)行,我們也可以使用UNIONALL來提高性能。
但是UnionAll性能一般來說比Union要好,但是比Join要差。
杳看它們的運(yùn)行結(jié)果,可以發(fā)現(xiàn)運(yùn)行結(jié)果是相同的,現(xiàn)在來分析一卜它們的執(zhí)行計(jì)劃和性能差別:
SELECT*FROMDBO.SALESWHEREQTY<10UNIONSELECT-FROMDBO.SALESWHEREQTY>11
□
SortClusteredIndexScan
SELECT
(DistinctSort)[pubi].[dbo].[sales].[UPKCL^salts]
Cost:0%
Cost:L3%Cost:43%
CluBteredIndexScan
[pub?].[dbo].[Balei].[OTKCL_sale?]
Cost:43%
Query2:Querycost(relatiretothebatch):30%
SELECTdistinct*FROMDBO.SALESWHEREQTY<10ORQTY>11
□
ClusteredIndexScan
SELECT
[pubs].[^o].[sales].[UPKd_saies]
Cost:0%
Cost:100,
可見使用UNION時(shí)執(zhí)行兩次CLUSTERED索引的掃描,并且要把結(jié)果使用DISTINCT合并起
來,而第二個查詢只要進(jìn)行一次CLUSTERED索引進(jìn)行掃描,然后直接展現(xiàn)出來,從而大大提
高了性能。
但是如果能夠使用JOIN達(dá)到目的的話,我們建議不要使用Union和UnionALL而是直接使
用JOIN來取我們需要的數(shù)據(jù)。
4.1.5Distinct
有開發(fā)人員在寫查詢的時(shí)候不管是否需要都習(xí)慣性的在查詢中寫上DISTINCT,這是一個很不好
的習(xí)慣,特別是當(dāng)我們的查詢中包含很大數(shù)據(jù)量的時(shí)候更會大大消耗有限的數(shù)據(jù)庫資源并降低的
應(yīng)用程序性能。
DISTINCT應(yīng)該在確認(rèn)結(jié)具集中存在重復(fù)行,并且這些重復(fù)的確數(shù)據(jù)并不是我們所需要的數(shù)據(jù)
時(shí)才能夠使用。這是因?yàn)镈ISTINCT在數(shù)據(jù)庫上執(zhí)行了很多額外的操作從而消耗了很多數(shù)據(jù)庫
資源,這樣會減少別的查詢在執(zhí)行時(shí)所能夠使用的資源,增加數(shù)據(jù)庫出現(xiàn)性能問題的幾率,
例子:
USEPUBS;
GO
SELECTDISTINCT
au_fnamez
au_lname
FROMauthors
這是一個非常簡單的SELECTDISTINCT查詢語句的示例,但是當(dāng)我們執(zhí)行一個復(fù)雜的語句時(shí)
就應(yīng)該考慮重新編碼以達(dá)到性能的要求,如下面的語句,當(dāng)返回authore表中已經(jīng)出版過書的
作者時(shí),很多人會像下面這樣寫:
SELECTDISTINCT
au_fnamez
au_lname
FROMauthorsaJOtitleAuthort
ONt.auid=a.auid
但這時(shí)只想得到作者名字,我們可以重寫這個語句來提升我們查詢語句的性能:
SELECTau_fname,
au_lname
FROMauthorsa
WHEREEXISTS(
SELECT*
FROMtitleAuthort
WHEREt.au_ida.au_id
上面的查詢能夠提升性能是因?yàn)槿绻硞€作者出過很多書,當(dāng)查到這個作者出版的第一條記錄
時(shí),就會停止對這個作者的處理。
我們要慎重考慮是不是真的需要DISTINCT
4.1.6TOPN
如果我們的應(yīng)用程序要返回上千行乃至上萬行數(shù)據(jù)的時(shí)候,我們要考慮是不是真正的需要這么多
數(shù)據(jù),是不是可以使用TOP操作符來限制返回給客戶端的行數(shù)或者返向給客戶端結(jié)果集行的百
分比,這樣可以減少資源的使用,提高數(shù)據(jù)庫性能并且有效節(jié)省帶寬
下面說一下關(guān)于減少網(wǎng)絡(luò)傳輸壓力的內(nèi)容。如果我們每次多返回給客戶端10行數(shù)據(jù),每行多返
回200個字節(jié),每天10000次被執(zhí)行,這就是一筆不小的網(wǎng)絡(luò)傳輸成本
(10*200*10000Byte),另外,如果再加上傳輸圖片等,將耍占用更多的帶寬。
例子:
USEPUBS;
GO
SELECTTOP1FNAME,LNAME,HIRE_DATEFROMDBO.EMPLOYEE
WHERELNAME'A*'
這時(shí)如果有100,000行數(shù)據(jù)符合WHERE條件,也只返回限制的1行結(jié)果集。因?yàn)镾QLServer
在處理時(shí),當(dāng)結(jié)果集的行數(shù)達(dá)到TOP中指定的數(shù)目時(shí),所有的處理都將停止,這樣就可以潛在
的提高SQLServer的負(fù)載,增加性能。
此外,TOP操作還可以讓我們指定返回給客戶端結(jié)果集行數(shù)的百分比,如:
USEPUBS;
GO
SELECTTOP1PERCENTFNAME,LNAMEfHIRE_DATEFROMDBO.EMPLOYEE
WHERELNAMELIKE*A%'
NOTE:如果?個SELECT語句既包含TOP又包含ORDERBY了?句,那么返回的行將會
從排序好的結(jié)果集中選擇,并且只返回已排好序結(jié)果集的前n行(或者前百分之N行)。
4.1.7InAndExist
當(dāng)我們能夠在我們的杳詢中選擇使用IN和Exist語句時(shí),推薦使用EXISTS,因?yàn)镋XISTS一
般更加高效(EXIST只遇到附合條件的很第一個結(jié)果時(shí),此記錄就退出處理)。
4.1.8InandBetween
在兗詢語句中選擇使用IN和BETWEEN時(shí),建議使用BETWEEN,因?yàn)樗诤芏鄨龊舷赂咝А?/p>
例子:有一個customer表,在customer_number列上有一個非聚集索引,進(jìn)行如下查詢:
SELECTcustomer_number,customer_name
FROMcustomer
WHEREcustomer_numberin(1000,1001,1002,1003,1004)
查詢優(yōu)化器可以使我們下面使用BETWEEN的語句比使用IN的語句性能更高效:
SELECTcustomer_numberzcustomer_name
FROMcustomer
WHEREcustomer_numberBETWEEN1000and1004
4.1.9Like
當(dāng)在WHERE中使用Like時(shí),盡可能的在Like語句中使用一個或者多個前導(dǎo)字符,比如:
使用
而不是:
%m
如果在Like中使用一個前導(dǎo)字符,此時(shí)查詢優(yōu)化器就會自動使用相應(yīng)索引(如果有合適索引存
在的話)來處理這個杳詢,但是如果我們Like語句中的前導(dǎo)字符使用通配符,杳聞優(yōu)化器不會
使用索引,而會對表進(jìn)行掃描,從而大大降低性能。這點(diǎn)在SQLServer2005卜.有所提升,
在SQLServer2005中,置詢優(yōu)化器可以為類似于LIKE,%m'語句使用索引。
NOTE:使用的前導(dǎo)字符越多,查詢優(yōu)化器就越有可能找到合適的索引,從而加快查詢。
另外,如果應(yīng)用程序的查詢中有很多對CHAR和VARCHAR列進(jìn)行Like操作時(shí),我們可能要
考慮使用SQLServer的全文索引,全文索引對于處理這方面查詢會大大提升性能。
4.1.10OR
如果一個查詢語句中包括多個OR子句,為提升性能,一般情況下可以重寫為一系列查詢并使用
UNIONALL來合并結(jié)果集。
例子:
SELECTemployeelD,firstname,lastname
FROMnames
WHEREdept=*prod*orcity=*Orlando'ordivision=*food,
這個語句在WHERE中有三個獨(dú)立的條件,為了使用到索引,我們要在這三列上創(chuàng)建組合索引。
像這樣的語句可能被重寫為多個查詢并使用UNIONALL來合并結(jié)果集,從而替代OR操作。
如下:
SELECTemployeelD,firstname,lastnameFROMnamesWHEREdept'prod'
SELECTemployeelD,firstname,lastnameFROMnamesWHEREcity'Orlando,
SELECTemployeelD,firstname,lastnameFROMnamesWHEREdivision1food,
每一個查詢都得出一樣的結(jié)果集(元數(shù)據(jù)相同),如果在這個表中只有dept列上存在索引,此
時(shí)第一個SELECT就會使用此索引,而第二個第三個SELECT語句會進(jìn)行表的掃描,而不是全
部進(jìn)行表的掃描。
這只是一個非常簡單的例子,只是示范了如何重寫查詢來提高性能,如果這個查詢比較復(fù)雜,那
么使用UNIONALL就會大大提高性能,因?yàn)檫@樣我們可以對每個語句進(jìn)行調(diào)整,而如果是全
在一個OR子句中,這些我們是做不到的。
NOTE:注意在這里我們是使用UNIONALL而不是UNION,原因是UNION不光會對結(jié)果集進(jìn)
行合并,也會對結(jié)果集進(jìn)行排序并移除所有的重復(fù)行,所以性能會大大降低。
4.1.11Orderby/sorting
ORDERBY要占用很多額外的資源,所以除非在真正需要的情況下,否則不要在SELECT語句
中使用ORDERBY.我們可以考慮,這些數(shù)據(jù)在客戶端進(jìn)行排序是否會更好,或者客戶端是否
需要我們對結(jié)果集進(jìn)行排序。
SORT一般是伴隨著以下T-SQL語句出現(xiàn):
>ORDERBY
>GROUPBY
>SELECTDISTINCT
>UNION
>CREATEINDEX(此時(shí)也需要對數(shù)據(jù)進(jìn)行排序)
一般情況下,這些命令不可能避免,但是另一方面,我們可能想辦法減少這些語句對資源的使用,
這包括:
>盡可能減少被排序的行數(shù),就是只對必要排序的數(shù)據(jù)行集進(jìn)行排序。
>盡可能減少結(jié)果臭中列的數(shù)目。
>盡可能減少所有行的物理寬度.
>盡可能對INT的列進(jìn)行排序,而不是Character或者Char列。
當(dāng)使用SORT操作時(shí),一定要考慮上面的建議,并保持下面的原則“除非必要,否則不要來對
結(jié)果集進(jìn)行排序”。
4.1.12Existandcount(*)
對數(shù)據(jù)庫進(jìn)行更新時(shí),很多時(shí)候要首先判斷被更新的記錄是否存在,或者對刪除對象之前,判斷
對象是否存在,此時(shí)不要使用SELECTCOUNT(*)來標(biāo)識,因?yàn)樗男阅苁欠浅5偷?。為了?/p>
升性能,我們可以使用IFEXISTS來實(shí)現(xiàn)相關(guān)的操作。IFEXISTS能提高性能是因?yàn)楫?dāng)有一條
記錄為真是,處理就會立即退出,但是COUNT(*)會檢查表中的每一條記錄的情況,不管符合
條件的數(shù)據(jù)有一條還是上萬條。
例子:
USEPUBS
--COUNT(*):
IF(SELECTCOUNT(*)FROMDBO.AUTHORS)>0
BEGIN
PRINT?ASDF,
END
--下面是使用EX工ST的語句,也是性能較好的語句:
IF■'XI(SELECTFROMDBO.AUTHORS
BEGIN
PRINT'ASDF'
END
看一下執(zhí)行計(jì)劃,可見使用EXIST確實(shí)能夠提高性能。
Query1:Querycost(relativetothebatch):85%
IF(SELECTCOUNT。FROMDSO.AUTHORS)>0
科一■5回
C3C&ScaXArCouutn3c?
Coae:0ICoat:0tiIDMZJoxalCom:0I
COM:0t
3鏘團(tuán)
:nS*SCAB
(Affxefawl①g,]」一】jMUmrg]
COM:0t
CF:01——100t
Query2:Querycost(relativetothebatch):15%
IFEXISTS(SELECT?FROMDBO.AUTHORS)
/q回
A___n
Loope
CONDConpureScalarConstantScan
Cost:0%Co?r:0?(LeftSeniJoin)Coir:0%
COST:0%
血
ZndaxScan
[pubs〕.IdboJ.(authors)(auniund]
Coit:100、
雖然這兩個杳詢語句都使用了一樣的索引,但是在COUN-(*)時(shí)返回的行的數(shù)據(jù)是表中符合條
件的所有行.然后才對這些行進(jìn)行Aggregate,這也就是為什么數(shù)據(jù)越多,使用COUNT(*)
性能越低的原因。
4.1.13使用Case
當(dāng)對一個表進(jìn)行多次更新時(shí),盡量合并到一個更新語句中。
例子:如果要對PUBS數(shù)據(jù)庫中的相關(guān)書根據(jù)不同的條件來調(diào)整它的銷售價(jià)格,需要調(diào)高商務(wù)
類書的銷售價(jià)格至原來的130%,調(diào)高非商務(wù)類書的銷售價(jià)格至原來的110%,我們很多人在
UPDATE的時(shí)候是以一個事務(wù)中包括兩個獨(dú)立的UPDATE語句來進(jìn)行的,如下:
BEGINTRAN
UPDATEtitlesSETpriceprice1.30WHEREtype'business'
UPDATEtitlesSETpriceprice1.10WHEREtype<>,business'
COMMITtran
上面語句的缺點(diǎn)是它會對表進(jìn)行兩次的讀寫,下面看一下如何把它們寫到一個語句中來:
UPDATEtitles
SETprice
CASE
WHENtype-1business
THENprice1.30
ELSEprice*1.10
END
比較一下下面的執(zhí)行計(jì)劃,發(fā)現(xiàn)第一個查詢語句的COST為66.7%,第二個查詢語句的COST
為33.3%.這樣就可以大大提高性能。
Query1:Querycost(relativetothebatch):33%
UPDATE[titles]SET[prxue]■[pirxce]?&】WHERE[type]?@2
CluydXndftxUpdateCIuiMz*dIndexScan
CcRpvScalasTop
[puba].[dbo].(tlclM).[U?KCLtitle[pubB].[dbo].CtlclM].nXPJCL
Cott:0%Cott:0%
Coe:22%-Co*t:78%
Query2:Querycost(relativetothebatch):33%
UPDATE[titles]SET[price]?[price]*81WHERE[type]<>82
n
UPDATEClusteredIndexUpdikeCospusScalarTopClusteredIndexScan
(pubs).(dbo].(titlts].EPKCL_xtl?」(pjbs).(dbol.(titles).
Coit:0?COST:0%Coir:0%
Coit:22%CoIX:78%
Query3:Querycost(relativetothebatch):33%
UPDATEtitlesSt工priu。.CAS£WHENtype.'business'HHENpriup1.32ELSEpr;u。,l?10END
回n。
ClustorMIndaxUpda^o-*ClusteredIndexSean
VPDA7EP
[pubs].[d^o].(cities].[UPKCLJ.0.Cpub?)?[So:.(titlM].lUPKCL^ltlei-
Coet:0%
Coet:22QCo":",
4.1.14NullVsNotNull
在創(chuàng)建表時(shí)應(yīng)該為每列創(chuàng)建默認(rèn)值而不是允許為NULL,因?yàn)閷煽樟羞M(jìn)行操作和對非可空列進(jìn)
行操作相比將需要更多額外的資源。如比較(comparisons)就是一個很好的例子。
所以我們應(yīng)該盡可能的使用NOTNULL來替代NULL。
4.1.15Bit
不推薦使用Bit歹人
如果已經(jīng)使用Bit歹U,請確保不要允許為NULL,如果此列有兩個以上的狀態(tài),請考慮其它類型。
4.1.16字符串操作
盡量避免在Transact-SQL中進(jìn)行字符的串聯(lián)操作,因?yàn)檫@是個很慢的操作,會造成應(yīng)用程序
的減慢(TSQL是為集合操作而優(yōu)化的)。
4.1.17在Where語句中存在冗余條件
在WHERE語句中小心地使用OR,這經(jīng)常會得到一些多余的數(shù)據(jù),同時(shí)也很容易在WHERE
語句中出現(xiàn)冗余的子句。
例子:
SELECTcompanyid,plantid,formulaid
FROMbatchrecords
WHERE(companyid10001'plantid,02021formulaid,39988773')
(companyid'0001'ndplantid=*0202,)
這兒的WHERE語句是冗余的:
companyid=100011andplantid-'0202*a::dformulaid=139988773,
是下面子句的子集:
companyid'00011mdplantid*0202,
換句話來說,這個查詢是冗余的,但SQLServer2000的查詢優(yōu)化器并不會自動探測是否存
在冗余(這個在SQLServer2005中有所提高),它完全按你所寫的條件去執(zhí)行,此時(shí)SQL
Server就會首先得到所有的數(shù)據(jù),然后使用SELECTDISTINCT來移除冗余的數(shù)據(jù)。如果刪
除以下的查詢子句:
companyid'0001*anciplantid*0202'
此時(shí)這個查詢語句就會加快很多。
4.1.18在WHERE子句中的列上使用函數(shù)
默認(rèn)情況下,在進(jìn)行比較時(shí),經(jīng)常寫類似下面的語句:
SELECTcolumn_nameFROMtable_name
WHERELOWERicolumn_name*name*
也就是說,大家認(rèn)為SQLServer是大小寫敏感的,但一般情況下我們SQLServer的配置為
大小寫不敏感,所以不使用類似于上面的語句,就可以大大加快查詢的速度。
但如果數(shù)據(jù)庫確實(shí)是配置為大小寫敏感時(shí),上面的代碼依然性能很低。因?yàn)樵瓌t是:不要在
WHERE中對列進(jìn)行任何函數(shù)操作,在列上進(jìn)行函數(shù)操作會導(dǎo)致此查詢并不能夠使用索引,如下:
SELECTmember_number,first_name,last_name
FROMmembers
WHEREDATEDIFF(yyzdatofbirth,GETDA7E())>21
如果需要進(jìn)行函數(shù)操作的話可以寫類似于下面的代碼,下面的代碼可以使用dateofbirth列上的
索引;
SELECTmember_number,first_name,last_name
FROMmembers
WHEREdateofbirthDATEADD(yy,-21,GETDATE())
4.1.19避免在WHERE中使用no-sargable
像“ISNULL","K'*,"NOT","NOTEXISTS","NOTIN","NOT
LIKE",和"LIKE'%50G”的操作一般來說將導(dǎo)致查詢優(yōu)化器不能夠使用索引來進(jìn)行數(shù)據(jù)的查
找。一般情況下,我們可以重寫這樣的語句來達(dá)到性能的提升。
例子:
下面語句:
WHERESUBSTRINGifirstname,1,1?m,
可能被重寫為下面的查詢:
WHEREfirstname*m%
NOT其實(shí)并不是no-sargable,但是一般情況下盡可能在查詢中查詢中不使用NOT操作符,
如:
WHERE\0Tcolumn_nane>5
可以被重寫為:
WHEREcolumnname<-5
4.1.20避免使用游標(biāo)
游標(biāo)可以嚴(yán)重影響SQLServe「性能,但是一些場合下不可避免,不過更多場合下我們是可以
不使用游標(biāo)的。所以如果現(xiàn)在你的應(yīng)用程序使用T-SQL游標(biāo),請重新檢杳你的代碼并盡可能的
重寫它們。
Transact-SQL是設(shè)計(jì)用來處理集合操作的,而不是對獨(dú)立的數(shù)據(jù)記錄行進(jìn)行操作。不過SQL
提供了一種對數(shù)據(jù)行進(jìn)行操作的選項(xiàng),在Transact-SQL中游標(biāo)就可以被用來處理獨(dú)立的行,
但是問題就是它的操作是如此慢,理想情況下,在高性能的基于SQLServer的應(yīng)用程序中,
游標(biāo)應(yīng)該被避免。
所以如果你要進(jìn)行一個基于行的操作,設(shè)法找到其它的方法來完成這項(xiàng)工作是一個非常好的開發(fā)
習(xí)慣??紤]使用以下選項(xiàng)來替代游標(biāo):
>使用臨時(shí)表
>使用WHILE循環(huán)
>使用derivedtables
>使用子查詢
>使用CASE語句
>使用多個查詢
上面的這些選項(xiàng)有時(shí)候可以替代游標(biāo),從而大大提升性能。但并不是所有的情況下都能夠使用以
上的選項(xiàng)來替代游標(biāo),如果發(fā)現(xiàn)不可能避免使用游標(biāo),請參考下面的建議或許會有幫助:
?SQLServer提供了兒種不同種類的游標(biāo),它們之間性能也存在著差異。我們要選擇對
服務(wù)器性能影響最小的能夠達(dá)到目標(biāo)的游標(biāo)。最高效的游標(biāo)就是fastforward-only游
標(biāo)。這個在我們的命名規(guī)范中也有提及
?當(dāng)使用游標(biāo)時(shí),取盡可能少的數(shù)據(jù)
?當(dāng)用過游標(biāo)后,不僅CLOSE它,同時(shí)也要DEALLOCATE此游標(biāo),也就是說游標(biāo)占用
的存儲單元也需要擇放,如果只是簡單的關(guān)閉而不擇放,雖然此游標(biāo)鎖死的資源被釋放,
但SQLServer的資源并沒有釋放,游標(biāo)使用的資源依然存在直到你釋放它為止。
SQLServer游標(biāo)非?常消耗數(shù)據(jù)庫資源,這是因?yàn)樗鼧O低的性能所致。但是根據(jù)“存在就是必然”
的原則(Montaque語錄),它們也有存在的道理,因?yàn)樵谟行┑胤绞谴_實(shí)非常有用的,它們非
常靈活?,可以使我們對每行的數(shù)據(jù)進(jìn)行非常靈活的操作,但一般情況下我們使用的游標(biāo)可能使用
其它方法來代替,比如DerivedTable,集合查詢和臨時(shí)麥,下面會討論一下這個問題。
下面討論游標(biāo)的可選替代方案。
這里通過一些示例來演示一下如何不使用游標(biāo)來解決一些以前用游標(biāo)來解決的問題。
例子:
首先,先看一下簡單的游標(biāo),此游標(biāo)在循環(huán)一個表,然后我們看一下如何不使用游標(biāo)來達(dá)到相同
的目標(biāo)。
使用游標(biāo):
ifexists(selectAfromsysobjectswherenameN*prcCursorExample')
dropprocedureprcCursorExample
go
CREATEPROCEDUREprcCursorExample
AS
/*
**putyourcommenthere
★*
*/
SETNOCOUNTON
--declareallvariables!
DECLAREQiRowIdint,
@vchCustomerNamenvarchar255),
@vchCustomerNmbrnvarchar10
-declarethecursor
DECLARECustomerCURSORFOR
SELECTiRowId,
vchCustomerNmbr.
vchCustomerName
FROMCustomerTable
OPENCustomer
FETCHCustomerINTO@iRowId,
@vchCustomerNmbr,
QvchCustomerName
--startthAmainp-ssHng1ccp.
WHILE@@Fetch_Status=0
BEGIN
——Thisiswhereyouperformyourdetailedrow-by-row
-processing.
——Getthenextrow.
FETCHCustomerINTO@iRowId,
^vchCustomerNmbrz
@vchCustomerName
END
CLOSECustomer
DEALLOCATECustomer
RETURN
不使用游標(biāo):
ifexists(selectfromsysobjectswherename=N*prcLoopExample')
dropprocedureprcLoopExample
g。
CREATEPROCEDUREprcLoopExample
AS
/*
**putyourcommenthere
*/
SETNOCOUNTON
--declareallvariables!
DECLAREQiReLuxiiCudeinL,
SiNextRowZdint,
QiCurrentRowIdint,
@iLoopControlint,
QvchCustonerNamenvarchar(255),
@vchCustonerNmbrnvarchar(10)
QchProductNumbernchar(30)
--Initializevariables!
SELECT@iLoopControl1
SELECT@iNextRowIdMIN(iRowId
FROMCustomerTable
Makesurethetablehasdata.
IFSN:」L.@iNextRow:d,00
BEGIN
SELECT'Nodatainfoundintable!1
RETURN
END
Retrievethefirstrow
SELECT@iCurrentRowIdiRowId,
@vchCustomerNmbrvchCustonerNmbr
@vchCustomerNamevchCustonerName
FROMCustomerTable
WHEREiRowZd@iNextRowId
startthemainprocessingloop.
WHILEGiLoopControl-1
BEGIN
Thisiswhereyouperformyourdetailedrow-by-row
processing.
Resetloopingvariables.
SELECTGiNextRowId
getthenextiRowId
SELECTGiNextRowIdMIN(iRowId)
FROMCustomerTable
WHEREiRov/idUiCurrentRowid
didwegetavalidnextrowid?
IFTSNUI/@iNextRowId,00
BEGIN
BREAK
END
getthenextrow.
SELECT0iCurrentRowIdiRowId.
@vchCustomerNmbrvchCustomerNmbr
@vchCustomerNamevchCustomerName
FROMCustomerTable
WHEREiRowIdQiNextRowId
END
RETURN
我們現(xiàn)在來看一下上面的游標(biāo),一般來說,為了性能的因素.我們的表上都有一個類似于RowID
的列,此列可以被用來做循環(huán),并得到相關(guān)的數(shù)據(jù)。一般來說此列是IDENTITY歹U,主鍵并有
clustered索引。
但是很多情況下,我們的表中并不包括可以被用來循環(huán)的行ID,比如,可能在一個具有
uniqueindentifier屬性的列上創(chuàng)建了主鍵索引,這時(shí)候可以為這個表增加一個自增列并創(chuàng)建相
應(yīng)的索引,來實(shí)現(xiàn)此功能。
卜.而例子使用了MIN函數(shù)和〃>"來得到下一行我們需要的數(shù)據(jù),當(dāng)然我們也可以使用MAX函
數(shù)然后使用〃達(dá)到相同的功能。
例子:
SELECT@iNextRowIdMAX(iRowId
FROMCustomerTable
WHEREiRowId<@iCurrentRowId
有一個比較重要的地方需要注意:要在取得下一次要循環(huán)的行ID之前設(shè)置此ID為NULL,是
因?yàn)楫?dāng)此循環(huán)實(shí)現(xiàn)所有的行循環(huán)后SELECT語句并不會為此ID設(shè)置為NULL,從而造成一個死
循環(huán)。當(dāng)循環(huán)變量為NULL后,意味著這個循環(huán)已經(jīng)完成了它需要實(shí)現(xiàn)的功能,此時(shí)我們可能
使用BREAK來退出WHILE循環(huán),當(dāng)然也有其它的途徑來推出循環(huán)。
你可以在上面的存儲過程中的如下注釋處加上自己的基于行的操作。
-Thisiswhereyouperformyourdetailedrow-by-rovz
--processing.
可以看出,基于行的操作對性能非常有影響。舉例來說,如果你有一個非常復(fù)雜的任務(wù)需要進(jìn)行
嵌套的循環(huán),此時(shí)你會使用嵌套的游標(biāo),內(nèi)層的游標(biāo)根據(jù)外層游標(biāo)的條件進(jìn)行相應(yīng)的操作,這時(shí)
候如果我們使用游標(biāo)來進(jìn)行處理的話對服務(wù)器會有非常大的壓力。
例子:
ifexist(select-fromsysobjectswhe
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年天然氣水合物開采技術(shù)預(yù)研報(bào)告:可燃冰開采技術(shù)裝備的智能化監(jiān)測與控制技術(shù)
- 自愿解除房產(chǎn)合同協(xié)議書
- 智力幽默測試題及答案
- 外企委托合同協(xié)議書
- 教學(xué)合作協(xié)議書合同模板
- 2025-2030中國豆耙餅行業(yè)需求前景預(yù)測及經(jīng)營效益咨詢研究報(bào)告
- 2025-2030中國西洋參行業(yè)市場發(fā)展現(xiàn)狀及前景趨勢與投資研究報(bào)告
- 什么事合同協(xié)議書
- pcr考試試題多選題及答案
- 2025年深??碧郊夹g(shù)產(chǎn)業(yè)鏈分析報(bào)告
- 上海市同濟(jì)大學(xué)第二附屬中學(xué)2024-2025學(xué)年八年級下冊期末物理試卷
- 2025年液壓馬達(dá)開發(fā)行業(yè)深度研究報(bào)告
- 樹木移栽施工協(xié)議書
- 手術(shù)前抗凝藥停用時(shí)間
- 租地解除合同協(xié)議書
- 2025智能礦山暨無人駕駛行業(yè)藍(lán)皮書-億歐智庫
- 2025湖北水發(fā)集團(tuán)園招聘40人筆試參考題庫附帶答案詳解
- 2025年人工智能應(yīng)用技術(shù)考試試題及答案
- 2024北森圖形推理題
- 2025年全國國家版圖知識競賽賽(附答案)
- 2025年社區(qū)工作者考試試題及答案
評論
0/150
提交評論