SQL Server中的重要观点
以下為重要觀點(diǎn):
1、通過(guò)把數(shù)據(jù)庫(kù)設(shè)置成讀已提交快照,在read committed隔離級(jí)別下,讀不會(huì)阻塞寫(xiě),寫(xiě)也不會(huì)阻塞讀,通過(guò)嘗試這個(gè)觀點(diǎn)是正確的。
2、當(dāng)連接1請(qǐng)求了共享鎖,2請(qǐng)求了獨(dú)占鎖,3請(qǐng)求了共享鎖,4請(qǐng)求了更新鎖時(shí),這四個(gè)請(qǐng)求都會(huì)進(jìn)入鎖的請(qǐng)求隊(duì)列中,書(shū)上說(shuō)SQL Server的鎖隊(duì)列,基本上是按照先進(jìn)先出的規(guī)則,但是會(huì)考慮鎖的兼容性,所以這個(gè)時(shí)候可能1、3、4這3個(gè)請(qǐng)求的鎖是兼容的,所以這3個(gè)請(qǐng)求會(huì)先處理,這個(gè)得嘗試一下
一個(gè)優(yōu)化方面的重要的觀點(diǎn)
網(wǎng)友的提問(wèn):
大牛們,加了一個(gè)or,為什么執(zhí)行計(jì)劃由哈希匹配變成嵌套循環(huán)?http://bbs.csdn.net/topics/390599501
select count(*) from t1 where a1='1' and a2 in(select a2 from t2)
select count(*) from t1 where a1='1' and (a2 in(select a2 from t2) or a2='2')
表t1超過(guò)100萬(wàn)條數(shù)據(jù),語(yǔ)句1執(zhí)行時(shí)間為1秒,語(yǔ)句2超過(guò)80秒,請(qǐng)問(wèn)為什么,語(yǔ)句2該怎樣修改?
下面是我的回答:
建議把查詢(xún)改寫(xiě)成關(guān)聯(lián)的,inner join或者是left join,其實(shí)要想明白,為什么加了a2='2'后,執(zhí)行計(jì)劃變化了,這個(gè)很難,因?yàn)檫@個(gè)是由SQL Server的優(yōu)化器決定的,我們很難猜測(cè)優(yōu)化器在一堆的判斷當(dāng)中為什么選了nested loop 而不選hash join。
但如果你寫(xiě)成inner join或者left join的時(shí)候,如果速度不佳,你可以通過(guò)添加查詢(xún)提示,比如hash:inner hash join
其實(shí)本質(zhì)上就是手動(dòng)給SQL Server的優(yōu)化器建議,建議他采用hash join,之所以微軟會(huì)提供這種查詢(xún)提示,就是已經(jīng)預(yù)料到會(huì)有你所遇到的問(wèn)題,所以才提供了這種可以由你來(lái)進(jìn)行微調(diào)的技術(shù)。
?
下面是一個(gè)關(guān)于數(shù)據(jù)庫(kù)設(shè)計(jì)的觀點(diǎn)
下面是網(wǎng)友的一個(gè)問(wèn)題:http://bbs.csdn.net/topics/390631703?page=1#post-395959332
關(guān)于倉(cāng)儲(chǔ)系統(tǒng)的方案設(shè)計(jì),以下為現(xiàn)有倉(cāng)庫(kù)表的設(shè)計(jì)(部分表):
TAB/裝車(chē)單:
字段:(裝車(chē)單號(hào),倉(cāng)庫(kù)ID,倉(cāng)庫(kù)編碼,倉(cāng)庫(kù)名稱(chēng),...創(chuàng)建人NAME,創(chuàng)建時(shí)間,修改人NAME,修改時(shí)間...)
TAB/裝車(chē)單明細(xì)表:
字段:(裝車(chē)單號(hào),貨物ID,貨物名稱(chēng),...創(chuàng)建人NAME,創(chuàng)建時(shí)間,修改人NAME,修改時(shí)間...)
TAB/采購(gòu)單:
字段:(采購(gòu)單號(hào),...創(chuàng)建人NAME,創(chuàng)建時(shí)間,修改人NAME,修改時(shí)間...)
TAB/采購(gòu)單明細(xì)表:
字段:(進(jìn)貨商ID,進(jìn)貨商N(yùn)AME,采購(gòu)部門(mén)ID,采購(gòu)部門(mén)NAME,...創(chuàng)建人NAME,創(chuàng)建時(shí)間,修改人NAME,修改時(shí)間...驗(yàn)貨人NAME,驗(yàn)貨時(shí)間)
?
首先這個(gè)不我設(shè)計(jì)的,我覺(jué)那個(gè)人這樣的設(shè)計(jì)的好處就是為了查詢(xún)方便(不用做關(guān)聯(lián)查詢(xún)嵌套查詢(xún)什么的就能獲得要的數(shù)據(jù)),但是一旦部門(mén)名稱(chēng)或者管理員名稱(chēng)(即便可能不修改 但不是絕對(duì)的)等等會(huì)影響到所有使用這些數(shù)據(jù)的表。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
我的解決方案
我看到這個(gè)庫(kù)時(shí)候感覺(jué)里面太多太多的表都都是這樣的,舉個(gè)最明顯的例子,創(chuàng)建人NAME 好多表都存的是 管理員的NAME 而非ID。
我覺(jué)的除了把管理員NAME之類(lèi)的刪除,都換成外鍵。除此 像裝車(chē)單里的倉(cāng)庫(kù)編碼、倉(cāng)庫(kù)名稱(chēng)、等;裝車(chē)明細(xì)表里的貨物名稱(chēng);采購(gòu)單明細(xì)里的采購(gòu)部門(mén)NAME,進(jìn)貨商N(yùn)AME都統(tǒng)統(tǒng)刪除 只保留引用的外鍵ID進(jìn)行設(shè)計(jì)
之所以這樣修改是為了解決數(shù)據(jù)冗余問(wèn)題,但后期在查詢(xún)數(shù)據(jù)時(shí)候會(huì)涉及更多的嵌套查詢(xún)關(guān)聯(lián)查詢(xún)才能解決。不知道各位老蝦怎么看我這樣的處理方案或者給個(gè)更好的意見(jiàn),多謝
===============================================================================
?
下面是我的回復(fù):
其實(shí),你對(duì)于表的修改意見(jiàn),是有道理的。
因?yàn)?#xff0c;關(guān)系數(shù)據(jù)庫(kù)系統(tǒng),在設(shè)計(jì)時(shí),有所謂3NF,一般都要達(dá)到這個(gè)第三范式,這樣能夠減少數(shù)據(jù)的冗余。
而且,實(shí)際上不僅能夠減少冗余,而且這樣做的好處是由于是通過(guò)外鍵來(lái)引用基表的id,修改也方便了,
比如,當(dāng)你的倉(cāng)庫(kù)名稱(chēng)變化了,你只需要去修改,這些業(yè)務(wù)表所引用的,基表里面的倉(cāng)庫(kù)名稱(chēng)。
而你們公司現(xiàn)在的系統(tǒng),如果你有10個(gè)業(yè)務(wù)表,都有倉(cāng)庫(kù)名稱(chēng)這個(gè)字段,一旦只要有一個(gè)倉(cāng)庫(kù)的名稱(chēng)變化了,那么你就得通過(guò)倉(cāng)庫(kù)編號(hào),來(lái)連接基表,然后再u(mài)pdate這10個(gè)表的倉(cāng)庫(kù)名稱(chēng),那是非常麻煩的。
應(yīng)該說(shuō),你們公司現(xiàn)在系統(tǒng)的數(shù)據(jù)存儲(chǔ)方式是采用了反向規(guī)范化,也就是冗余化存儲(chǔ)。
你希望采用規(guī)范化,而你們公司原來(lái)的系統(tǒng)采用的是范規(guī)范化。
規(guī)范化的好處上面說(shuō)了,就是減少數(shù)據(jù)冗余,修改非常容易。
而反向規(guī)范化的好處,就是不用子查詢(xún),或者關(guān)聯(lián)多的表,查詢(xún)的性能會(huì)好。
總結(jié):
我覺(jué)得到底采用哪種方式,這需要你自己權(quán)衡,如果你的系統(tǒng),很少有更新倉(cāng)庫(kù)名稱(chēng),也就是很少更新這些基表數(shù)據(jù),那么為了提高查詢(xún)的性能,而且也不用每次寫(xiě)查詢(xún),關(guān)聯(lián)N多基表,那么就還是采用原來(lái)的方式。這種方式,在互聯(lián)網(wǎng)的應(yīng)用中比較多,傳統(tǒng)的業(yè)務(wù)用的不多。
如果系統(tǒng)中會(huì)更新這些倉(cāng)庫(kù)名稱(chēng),那么還是建議采用外鍵id的方式,來(lái)修改這些表的設(shè)計(jì),當(dāng)然啦,語(yǔ)句可能得寫(xiě)的比較復(fù)雜,因?yàn)槲以瓉?lái)的公司就是都采用外鍵id的,由于這種外鍵很多,公司設(shè)計(jì)了一個(gè)字典表,
比如:dict_table 里面存放了幾乎所有的外鍵id,所引用的id,那么我們公司有一個(gè)store表,里面有一堆的id,上面渠道id,公司id,組織id,經(jīng)銷(xiāo)商id,層級(jí)id,性質(zhì)id等,于是乎,為了取得這些客戶(hù)的渠道、公司、組織、經(jīng)銷(xiāo)商、層級(jí)、性質(zhì),就得關(guān)聯(lián)dict_table 至少6次,也就是
select 字段列表
from store
left join dict_table
left join dict_table
left join dict_table
left join dict_table
left join dict_table
left join dict_table
就是這樣,經(jīng)常一個(gè)查詢(xún),得關(guān)聯(lián)10-15個(gè)表左右,語(yǔ)句寫(xiě)的非常復(fù)雜。
所以,呵呵,最后還是得樓主,按照你們公司的特殊情況,業(yè)務(wù)特點(diǎn),來(lái)選擇,到底是去除冗余,或者是去除部分冗余。
還有下面的,關(guān)于數(shù)據(jù)庫(kù)設(shè)計(jì)的:
我也試了,如果把數(shù)據(jù)拆分成列,那么到時(shí)候,比如:屬性-值,拆分成2行數(shù)據(jù),一行存屬性,一行存列,
這樣看上去倒是好一點(diǎn),但是在查詢(xún)的時(shí)候,還是得行轉(zhuǎn)列,比較麻煩。
其實(shí)設(shè)計(jì)表,就是得考慮:性能,業(yè)務(wù),占用存儲(chǔ),開(kāi)發(fā)速度。
我原來(lái)的公司,需要非常快的開(kāi)發(fā)速度,于是,就把不同業(yè)務(wù)的數(shù)據(jù),放到一個(gè)表中,通過(guò)增加一個(gè)func_code字段,來(lái)區(qū)分是不同功能產(chǎn)生的,然后后面是一堆字段,A業(yè)務(wù)用xx字段,B業(yè)務(wù)用yy字段,其他都是空著的,這樣的話,非常方便開(kāi)發(fā),在理解業(yè)務(wù)的時(shí)候,也很容易,不同業(yè)務(wù),用不同的字段。
但是,如果你不懂業(yè)務(wù),就會(huì)很迷惑,看不懂,怎么一眼看過(guò)去,一堆沒(méi)用的字段放在那兒,全是null。
也想過(guò)拆分,但是這樣也麻煩,就是剛才說(shuō)的,開(kāi)發(fā)的難度就上去了,而且性能也不會(huì)太好,因?yàn)槟愕米鰟?dòng)態(tài)的行轉(zhuǎn)列,每個(gè)業(yè)務(wù)用到的字段個(gè)數(shù),和字段名稱(chēng),都不完全一樣,這可非常的麻煩。
所以,你一開(kāi)始想的還是對(duì)的,這種表的設(shè)計(jì),雖然看著,有很多null值,但是開(kāi)發(fā)上就比較容易,性能也不錯(cuò)。
關(guān)于通過(guò)游標(biāo)和循環(huán)的方式來(lái)處理數(shù)據(jù)的問(wèn)題:
其實(shí)用循環(huán)和游標(biāo),之所以對(duì)性能有影響,根本的原因在于,處理數(shù)據(jù)的方式,也就是取出1條數(shù)據(jù),然后處理,處理完成后,再取出下一條,
如果你的表有1000w條數(shù)據(jù),那么就得循環(huán)1000w次,效率肯定是非常低的。
同樣的,如果單純的sql語(yǔ)句,之所以性能相對(duì)較好的原因在于,他是以集合為單位來(lái)處理數(shù)據(jù),也就是批處理,一次能把所有的數(shù)據(jù)都處理好。
當(dāng)然,有時(shí)候,由于業(yè)務(wù)邏輯非常復(fù)雜,可能需要寫(xiě)多個(gè)語(yǔ)句,每個(gè)語(yǔ)句先把中間的結(jié)果插入到一個(gè)臨時(shí)表中,然后最后再對(duì)臨時(shí)表進(jìn)行處理,這也是一個(gè)變通的辦法,但盡量不要用游標(biāo)或者是循環(huán)來(lái)處理數(shù)據(jù),因?yàn)樾时容^低。
?
轉(zhuǎn)載于:https://www.cnblogs.com/momogua/archive/2012/02/05/8304637.html
總結(jié)
以上是生活随笔為你收集整理的SQL Server中的重要观点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: css字体设置奇怪问题
- 下一篇: Zend Framework数据库操作(