有关T-SQL的10个好习惯
1.在生產(chǎn)環(huán)境中不要出現(xiàn)Select *
???? 這一點(diǎn)我想大家已經(jīng)是比較熟知了,這樣的錯(cuò)誤相信會(huì)犯的人不會(huì)太多。但我這里還是要說一下。
???? 不使用Select *的原因主要不是坊間所流傳的將*解析成具體的列需要產(chǎn)生消耗,這點(diǎn)消耗在我看來完全可以忽略不計(jì)。更主要的原因來自以下兩點(diǎn):
- ???? 擴(kuò)展方面的問題
- ???? 造成額外的書簽查找或是由查找變?yōu)閽呙?/li>
???? 擴(kuò)展方面的問題是當(dāng)表中添加一個(gè)列時(shí),Select *會(huì)把這一列也囊括進(jìn)去,從而造成上面的第二種問題。
???? 而額外的IO這點(diǎn)顯而易見,當(dāng)查找不需要的列時(shí)自然會(huì)產(chǎn)生不必要的IO,下面我們通過一個(gè)非常簡(jiǎn)單的例子來比較這兩種差別,如圖1所示。
???
??? 圖1.*帶來的不必要的IO
?
2.聲明變量時(shí)指定長(zhǎng)度
??? 這一點(diǎn)有時(shí)候會(huì)被人疏忽,因?yàn)閷?duì)于T-SQL來說,如果對(duì)于變量不指定長(zhǎng)度,則默認(rèn)的長(zhǎng)度會(huì)是1.考慮下面這個(gè)例子,如圖2所示。
???
??? 圖2.不指定變量長(zhǎng)度有可能導(dǎo)致丟失數(shù)據(jù)
?
3.使用合適的數(shù)據(jù)類型
??? 合適的數(shù)據(jù)類型首先是從性能角度考慮,關(guān)于這一點(diǎn),我寫過一篇文章詳細(xì)的介紹過,有興趣可以閱讀:對(duì)于表列數(shù)據(jù)類型選擇的一點(diǎn)思考,這里我就不再細(xì)說了
?? 不要使用字符串類型存儲(chǔ)日期數(shù)據(jù),這一點(diǎn)也需要強(qiáng)調(diào)一些,有時(shí)候你可能需要定義自己的日期格式,但這樣做非常不好,不僅是性能上不好,并且內(nèi)置的日期時(shí)間函數(shù)也不能用了。
?
4.使用Schema前綴來選擇表
??? 解析對(duì)象的時(shí)候需要更多的步驟,而指定Schema.Table這種方式就避免了這種無謂的解析。
??? 不僅如此,如果不指定Schema容易造成混淆,有時(shí)會(huì)報(bào)錯(cuò)。
??? 還有一點(diǎn)是,Schema使用的混亂有可能導(dǎo)致更多的執(zhí)行計(jì)劃緩存,換句話說,就是同樣一份執(zhí)行計(jì)劃被多次緩存,讓我們來看圖3的例子。
???
??? 圖3.不同的schema選擇不同導(dǎo)致同樣的查詢被多次緩存
?
5.命名規(guī)范很重要
??? 推薦使用實(shí)體對(duì)象+操作這種方式,比如Customer_Update這種方式。在一個(gè)大型一點(diǎn)的數(shù)據(jù)庫會(huì)存在很多存儲(chǔ)過程,不同的命名方式使得找到需要的存儲(chǔ)過程變得很不方便。因此有可能造成另一種問題,就是重復(fù)創(chuàng)建存儲(chǔ)過程,比如上面這個(gè)例子,有可能命名規(guī)范不統(tǒng)一的情況下又創(chuàng)建了一個(gè)叫UpdateCustomer的存儲(chǔ)過程。
?
6.插入大量數(shù)據(jù)時(shí),盡量不要使用循環(huán),可以使用CTE,如果要使用循環(huán),也放到一個(gè)事務(wù)中
??? 這點(diǎn)其實(shí)顯而易見。SQL Server是隱式事務(wù)提交的,所以對(duì)于每一個(gè)循環(huán)中的INSERT,都會(huì)作為一個(gè)事務(wù)提交。這種效率可想而知,但如果將1000條語句放到一個(gè)事務(wù)中提交,效率無疑會(huì)提升不少。
??? 打個(gè)比方,去銀行存款,是一次存1000效率高,還是存10次100?下面,根據(jù)吉日的要求,補(bǔ)個(gè)例子,見代碼1.
CREATE TABLE dbo.TestInsert (Number INT PRIMARY KEY ); --循環(huán)插入,不給力,我的筆記本45秒 DECLARE @index INT; SET @index = 1;WHILE @index <= 100000 BEGININSERT dbo.TestInsert(Number) VALUES( @index);SET @index = @index + 1; END--放到一個(gè)事務(wù)中循環(huán),略好,但也不是最好,我的筆記本1秒 BEGIN TRAN DECLARE @index INT; SET @index = 1;WHILE @index <= 100000 BEGININSERT dbo.TestInsert(Number) VALUES( @index);SET @index = @index + 1; ENDCOMMIT--批量插入,10W行,顯示0秒,有興趣的同學(xué)改成100W行進(jìn)行測(cè)試 INSERT dbo.TestInsert(Number)SELECT TOP (100000) rn = ROW_NUMBER() OVER(ORDER BY c1.[object_id])FROM sys.columns AS c1CROSS JOIN sys.columns AS c2CROSS JOIN sys.columns AS c3ORDER BY c1.[object_id];--CTE方式,和上面那種方式大同小異,也是批量插入,比如: WITH cte AS(SELECT TOP (100000) rn = ROW_NUMBER() OVER(ORDER BY c1.[object_id])FROM sys.columns AS c1CROSS JOIN sys.columns AS c2CROSS JOIN sys.columns AS c3ORDER BY c1.[object_id] ) INSERT dbo.TestInsert(Number) SELECT rn FROM cte??? 代碼1.幾種插入方式的比較
?
?
7.where條件之后盡量減少使用函數(shù)或數(shù)據(jù)類型轉(zhuǎn)換
?
?? 換句話說,WHERE條件之后盡量可以使用可以嗅探參數(shù)的方式,比如說盡量少用變量,盡量少用函數(shù),下面我們通過一個(gè)簡(jiǎn)單的例子來看這之間的差別。如圖4所示。
??
??? 圖4.在Where中使用不可嗅探的參數(shù)導(dǎo)致的索引查找
?
??? 對(duì)于另外一些情況來說,盡量不要讓參數(shù)進(jìn)行類型轉(zhuǎn)換,再看一個(gè)簡(jiǎn)單的例子,我們可以看出在Where中使用隱式轉(zhuǎn)換代價(jià)巨大。如圖5所示。
???
??? 圖5.隱式轉(zhuǎn)換帶來的性能問題
?
8.不要使用舊的連接方式,比如(from x,y,z)
??? 可能導(dǎo)致效率低下的笛卡爾積,當(dāng)你看到下面這個(gè)圖標(biāo)時(shí),說明查詢分析器無法根據(jù)統(tǒng)計(jì)信息估計(jì)表中的數(shù)據(jù)結(jié)構(gòu),所以無法使用Loop join,merge Join和Hash Join中的一種,而是使用效率地下的笛卡爾積。
>?? 這里我再補(bǔ)充一點(diǎn),我說得是“可能”導(dǎo)致,因?yàn)樯厦孢@個(gè)查詢可能作為中間結(jié)果或是子查詢,當(dāng)你忘寫了where條件時(shí),會(huì)是笛卡爾積。你在最終結(jié)果中再用where過濾,可能得到的結(jié)果一模一樣,但是中間的過程卻大不相同
???
?
??? 所以,盡量使用Inner join的方式替代from x,y,z這種方式。
?
9.使用游標(biāo)時(shí),加上只讀只進(jìn)選項(xiàng)
?
??? 首先,我的觀點(diǎn)是:游標(biāo)是邪惡的,盡量少用。但是如果一定要用的話,請(qǐng)記住,默認(rèn)設(shè)置游標(biāo)是可進(jìn)可退的,如果你僅僅設(shè)置了
declare c cursorfor??? 這樣的形式,那么這種游標(biāo)要慢于下面這種方式。
???? ???
declare c cursorlocal static read_only forward_onlyfor…?
??? 所以,在游標(biāo)只讀只進(jìn)的情況下,加上上面代碼所示的選項(xiàng)。
?
10.有關(guān)Order一些要注意的事情
??? 首先,要注意,不要使用Order by+數(shù)字的形式,比如圖6這種。
???
??? 圖6.Order By序號(hào)
?
??? 當(dāng)表結(jié)構(gòu)或者Select之后的列變化時(shí),這種方式會(huì)引起麻煩,所以老老實(shí)實(shí)寫上列名。
?
??? 還有一種情況是,對(duì)于帶有子查詢和CTE的查詢,子查詢有序并不代表整個(gè)查詢有序,除非顯式指定了Order By,讓我們來看圖7。
???
??? 圖7.雖然在CTE中中有序,但顯式指定Order By,則不能保證結(jié)果的順序
轉(zhuǎn)載于:https://www.cnblogs.com/toddzhang/p/3338149.html
總結(jié)
以上是生活随笔為你收集整理的有关T-SQL的10个好习惯的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: virtualenv wrapper安装
- 下一篇: 构建单层单向RNN网络对MNIST数据集