如何優(yōu)化數(shù)據(jù)庫(kù)的連接速度和查詢速度?
sql提高查詢效率
1.對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在where及orderby涉及的列上建立索引。
2.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行null值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
selectidfromtwherenumisnull
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒(méi)有null值,然后這樣查詢:
selectidfromtwherenum=0
3.應(yīng)盡量避免在where子句中使用!=或操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。
4.應(yīng)盡量避免在where子句中使用or來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
selectidfromtwherenum=10ornum=20
可以這樣查詢:
selectidfromtwherenum=10
unionall
selectidfromtwherenum=20
5.in和notin也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
selectidfromtwherenumin(1,2,3)
對(duì)于連續(xù)的數(shù)值,能用between就不要用in了:
selectidfromtwherenumbetween1and3
6.下面的查詢也將導(dǎo)致全表掃描:
selectidfromtwherenamelike'%abc%'
若要提高效率,可以考慮全文檢索。
7.如果在where子句中使用參數(shù),也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問(wèn)計(jì)劃的選擇推遲到運(yùn)行時(shí);它必須在編譯時(shí)進(jìn)行選擇。然而,如果在編譯時(shí)建立訪問(wèn)計(jì)劃,變量的值還是未知的,因而無(wú)法作為索引選擇的輸入項(xiàng)。如下面語(yǔ)句將進(jìn)行全表掃描:
selectidfromtwherenum=@num
可以改為強(qiáng)制查詢使用索引:
selectidfromtwith(index(索引名))wherenum=@num
8.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
selectidfromtwherenum/2=100
應(yīng)改為:
selectidfromtwherenum=100*2
9.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
selectidfromtwheresubstring(name,1,3)='abc'--name以abc開(kāi)頭的id
selectidfromtwheredatediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
應(yīng)改為:
selectidfromtwherenamelike'abc%'
selectidfromtwherecreatedate>='2005-11-30'andcreatedate
10.不要在where子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無(wú)法正確使用索引。
11.在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
12.不要寫(xiě)一些沒(méi)有意義的查詢,如需要生成一個(gè)空表結(jié)構(gòu):
selectcol1,col2into#tfromtwhere1=0
這類代碼不會(huì)返回任何結(jié)果集,但是會(huì)消耗系統(tǒng)資源的,應(yīng)改成這樣:
createtable#t(...)
13.很多時(shí)候用exists代替in是一個(gè)好的選擇:
selectnumfromawherenumin(selectnumfromb)
用下面的語(yǔ)句替換:
selectnumfromawhereexists(select1frombwherenum=a.num)
14.并不是所有索引對(duì)查詢都有效,SQL是根據(jù)表中數(shù)據(jù)來(lái)進(jìn)行查詢優(yōu)化的,當(dāng)索引列有大量數(shù)據(jù)重復(fù)時(shí),SQL查詢可能不會(huì)去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對(duì)查詢效率起不了作用。
15.索引并不是越多越好,索引固然可以提高相應(yīng)的select的效率,但同時(shí)也降低了insert及update的效率,因?yàn)閕nsert或update時(shí)有可能會(huì)重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個(gè)表的索引數(shù)最好不要超過(guò)6個(gè),若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有必要。
16.應(yīng)盡可能的避免更新clustered索引數(shù)據(jù)列,因?yàn)閏lustered索引數(shù)據(jù)列的順序就是表記錄的物理存儲(chǔ)順序,一旦該列值改變將導(dǎo)致整個(gè)表記錄的順序的調(diào)整,會(huì)耗費(fèi)相當(dāng)大的資源。若應(yīng)用系統(tǒng)需要頻繁更新clustered索引數(shù)據(jù)列,那么需要考慮是否應(yīng)將該索引建為clustered索引。
17.盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型,這會(huì)降低查詢和連接的性能,并會(huì)增加存儲(chǔ)開(kāi)銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接時(shí)會(huì)逐個(gè)比較字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比較一次就夠了。
18.盡可能的使用varchar/nvarchar代替char/nchar,因?yàn)槭紫茸冮L(zhǎng)字段存儲(chǔ)空間小,可以節(jié)省存儲(chǔ)空間,其次對(duì)于查詢來(lái)說(shuō),在一個(gè)相對(duì)較小的字段內(nèi)搜索效率顯然要高些。
19.任何地方都不要使用select*fromt,用具體的字段列表代替“*”,不要返回用不到的任何字段。
20.盡量使用表變量來(lái)代替臨時(shí)表。如果表變量包含大量數(shù)據(jù),請(qǐng)注意索引非常有限(只有主鍵索引)。
21.避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。
22.臨時(shí)表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行?,例如,?dāng)需要重復(fù)引用大型表或常用表中的某個(gè)數(shù)據(jù)集時(shí)。但是,對(duì)于一次性事件,最好使用導(dǎo)出表。
23.在新建臨時(shí)表時(shí),如果一次性插入數(shù)據(jù)量很大,那么可以使用selectinto代替createtable,避免造成大量log,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先createtable,然后insert。
24.如果使用到了臨時(shí)表,在存儲(chǔ)過(guò)程的最后務(wù)必將所有的臨時(shí)表顯式刪除,先truncatetable,然后droptable,這樣可以避免系統(tǒng)表的較長(zhǎng)時(shí)間鎖定。
25.盡量避免使用游標(biāo),因?yàn)橛螛?biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過(guò)1萬(wàn)行,那么就應(yīng)該考慮改寫(xiě)。
26.使用基于游標(biāo)的方法或臨時(shí)表方法之前,應(yīng)先尋找基于集的解決方案來(lái)解決問(wèn)題,基于集的方法通常更有效。
27.與臨時(shí)表一樣,游標(biāo)并不是不可使用。對(duì)小型數(shù)據(jù)集使用FAST_FORWARD游標(biāo)通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個(gè)表才能獲得所需的數(shù)據(jù)時(shí)。在結(jié)果集中包括“合計(jì)”的例程通常要比使用游標(biāo)執(zhí)行的速度快。如果開(kāi)發(fā)時(shí)間允許,基于游標(biāo)的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
28.在所有的存儲(chǔ)過(guò)程和觸發(fā)器的開(kāi)始處設(shè)置SETNOCOUNTON,在結(jié)束時(shí)設(shè)置SETNOCOUNTOFF。無(wú)需在執(zhí)行存儲(chǔ)過(guò)程和觸發(fā)器的每個(gè)語(yǔ)句后向客戶端發(fā)送DONE_IN_PROC消息。
29.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。
30.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過(guò)大,應(yīng)該考慮相應(yīng)需求是否合理
1、避免將字段設(shè)為“允許為空”
2、數(shù)據(jù)表設(shè)計(jì)要規(guī)范
3、深入分析數(shù)據(jù)操作所要對(duì)數(shù)據(jù)庫(kù)進(jìn)行的操作
4、盡量不要使用臨時(shí)表
5、多多使用事務(wù)
6、盡量不要使用游標(biāo)
7、避免死鎖
8、要注意讀寫(xiě)鎖的使用
9、不要打開(kāi)大的數(shù)據(jù)集
10、不要使用服務(wù)器端游標(biāo)
11、在程序編碼時(shí)使用大數(shù)據(jù)量的數(shù)據(jù)庫(kù)
12、不要給“性別”列創(chuàng)建索引
13、注意超時(shí)問(wèn)題
14、不要使用Select*
15、在細(xì)節(jié)表中插入紀(jì)錄時(shí),不要在主表執(zhí)行SelectMAX(ID)
16、盡量不要使用TEXT數(shù)據(jù)類型
17、使用參數(shù)查詢
18、不要使用Insert導(dǎo)入大批的數(shù)據(jù)
19、學(xué)會(huì)分析查詢
20、使用參照完整性
21、用INNERJOIN和LEFTJOIN代替Where
提高SQL查詢效率(要點(diǎn)與技巧):
·技巧一:
問(wèn)題類型:ACCESS數(shù)據(jù)庫(kù)字段中含有日文片假名或其它不明字符時(shí)查詢會(huì)提示內(nèi)存溢出。
解決方法:修改查詢語(yǔ)句
sql="select*fromtablenamewherecolumnlike'%"&word&"%'"
改為
sql="select*fromtablename"
rs.filter="columnlike'%"&word&"%'"
===========================================================
技巧二:
問(wèn)題類型:如何用簡(jiǎn)易的辦法實(shí)現(xiàn)類似百度的多關(guān)鍵詞查詢(多關(guān)鍵詞用空格或其它符號(hào)間隔)。
解決方法:
'//用空格分割查詢字符串
ck=split(word,"")
'//得到分割后的數(shù)量
sck=UBound(ck)
sql="select*tablenamewhere"
在一個(gè)字段中查詢
Fori=0Tosck
SQL=SQL&tempJoinWord&"("&_
"columnlike'"&ck(i)&"%')"
tempJoinWord="and"
Next
在二個(gè)字段中同時(shí)查詢
Fori=0Tosck
SQL=SQL&tempJoinWord&"("&_
"columnlike'"&ck(i)&"%'or"&_
"column1like'"&ck(i)&"%')"
tempJoinWord="and"
Next
===========================================================
技巧三:大大提高查詢效率的幾種技巧
1.盡量不要使用or,使用or會(huì)引起全表掃描,將大大降低查詢效率。
2.經(jīng)過(guò)實(shí)踐驗(yàn)證,charindex()并不比前面加%的like更能提高查詢效率,并且charindex()會(huì)使索引失去作用(指sqlserver數(shù)據(jù)庫(kù))
3.columnlike'%"&word&"%'會(huì)使索引不起作用
columnlike'"&word&"%'會(huì)使索引起作用(去掉前面的%符號(hào))
(指sqlserver數(shù)據(jù)庫(kù))
4.'%"&word&"%'與'"&word&"%'在查詢時(shí)的區(qū)別:
比如你的字段內(nèi)容為一個(gè)容易受傷的女人
'%"&word&"%':會(huì)通配所有字符串,不論查“受傷”還是查“一個(gè)”,都會(huì)顯示結(jié)果。
'"&word&"%':只通配前面的字符串,例如查“受傷”是沒(méi)有結(jié)果的,只有查“一個(gè)”,才會(huì)顯示結(jié)果。
5.字段提取要按照“需多少、提多少”的原則,避免“select*”,盡量使用“select字段1,字段2,字段3........”。實(shí)踐證明:每少提取一個(gè)字段,數(shù)據(jù)的提取速度就會(huì)有相應(yīng)的提升。提升的速度還要看您舍棄的字段的大小來(lái)判斷。
6.orderby按聚集索引列排序效率最高。一個(gè)sqlserver數(shù)據(jù)表只能建立一個(gè)聚集索引,一般默認(rèn)為ID,也可以改為其它的字段。
7.為你的表建立適當(dāng)?shù)乃饕?,建立索引可以使你的查詢速度提高幾十幾百倍。(指sqlserver數(shù)據(jù)庫(kù))
·以下是建立索引與不建立索引的一個(gè)查詢效率分析:
Sqlserver索引與查詢效率分析。
表News
字段
Id:自動(dòng)編號(hào)
Title:文章標(biāo)題
Author:作者
Content:內(nèi)容
Star:優(yōu)先級(jí)
Addtime:時(shí)間
記錄:100萬(wàn)條
測(cè)試機(jī)器:P42.8/1G內(nèi)存/IDE硬盤(pán)
=======================================================
方案1:
主鍵Id,默認(rèn)為聚集索引,不建立其它非聚集索引
select*fromNewswhereTitlelike'%"&word&"%'orAuthorlike'%"&word&"%'orderbyIddesc
從字段Title和Author中模糊檢索,按Id排序
查詢時(shí)間:50秒
=======================================================
方案2:
主鍵Id,默認(rèn)為聚集索引
在Title、Author、Star上建立非聚集索引
select*fromNewswhereTitlelike'"&word&"%'orAuthorlike'"&word&"%'orderbyIddesc
從字段Title和Author中模糊檢索,按Id排序
查詢時(shí)間:2-2.5秒
=======================================================
方案3:
主鍵Id,默認(rèn)為聚集索引
在Title、Author、Star上建立非聚集索引
select*fromNewswhereTitlelike'"&word&"%'orAuthorlike'"&word&"%'orderbyStardesc
從字段Title和Author中模糊檢索,按Star排序
查詢時(shí)間:2秒
=======================================================
方案4:
主鍵Id,默認(rèn)為聚集索引
在Title、Author、Star上建立非聚集索引
select*fromNewswhereTitlelike'"&word&"%'orAuthorlike'"&word&"%'
從字段Title和Author中模糊檢索,不排序
查詢時(shí)間:1.8-2秒
=======================================================
方案5:
主鍵Id,默認(rèn)為聚集索引
在Title、Author、Star上建立非聚集索引
select*fromNewswhereTitlelike'"&word&"%'
或
select*fromNewswhereAuthorlike'"&word&"%'
從字段Title或Author中檢索,不排序
查詢時(shí)間:1秒
·如何提高SQL語(yǔ)言的查詢效率?
問(wèn):請(qǐng)問(wèn)我如何才能提高SQL語(yǔ)言的查詢效率呢?
答:這得從頭說(shuō)起:
由于SQL是面向結(jié)果而不是面向過(guò)程的查詢語(yǔ)言,所以一般支持SQL語(yǔ)言的大型關(guān)系型數(shù)據(jù)庫(kù)都使用一個(gè)基于查詢成本的優(yōu)化器,為即時(shí)查詢提供一個(gè)最佳的執(zhí)行策略。對(duì)于優(yōu)化器,輸入是一條查詢語(yǔ)句,輸出是一個(gè)執(zhí)行策略。
一條SQL查詢語(yǔ)句可以有多種執(zhí)行策略,優(yōu)化器將估計(jì)出全部執(zhí)行方法中所需時(shí)間最少的所謂成本最低的那一種方法。所有優(yōu)化都是基于用記所使用的查詢語(yǔ)句中的where子句,優(yōu)化器對(duì)where子句中的優(yōu)化主要用搜索參數(shù)(SerachArgument)。
搜索參數(shù)的核心思想就是數(shù)據(jù)庫(kù)使用表中字段的索引來(lái)查詢數(shù)據(jù),而不必直接查詢記錄中的數(shù)據(jù)。
帶有=、、>=等操作符的條件語(yǔ)句可以直接使用索引,如下列是搜索參數(shù):
emp_id="10001"或salary>3000或a=1andc=7
而下列則不是搜索參數(shù):
salary=emp_salary或dep_id!=10或salary*12>=3000或a=1orc=7
應(yīng)當(dāng)盡可能提供一些冗余的搜索參數(shù),使優(yōu)化器有更多的選擇余地。請(qǐng)看以下3種方法:
第一種方法:
selectemployee.emp_name,department.dep_namefromdepartment,employeewhere(employee.dep_id=department.dep_id)and(department.dep_code="01")and(employee.dep_code="01");
它的搜索分析結(jié)果如下:
Estimate2I/Ooperations
Scandepartmentusingprimarykey
forrowswheredep_codeequals"01"
Estimategettinghere1times
Scanemployeesequentially
Estimategettinghere5times
第二種方法:
selectemployee.emp_name,department.dep_namefromdepartment,employeewhere(employee.dep_id=department.dep_id)and(department.dep_code="01");
它的搜索分析結(jié)果如下:
Estimate2I/Ooperations
Scandepartmentusingprimarykey
forrowswheredep_codeequals"01"
Estimategettinghere1times
Scanemployeesequentially
Estimategettinghere5times
第一種方法與第二種運(yùn)行效率相同,但第一種方法最好,因?yàn)樗鼮閮?yōu)化器提供了更多的選擇機(jī)會(huì)。
第三種方法:
selectemployee.emp_name,department.dep_namefromdepartment,employeewhere(employee.dep_id=department.dep_id)and(employee.dep_code="01");
這種方法最不好,因?yàn)樗鼰o(wú)法使用索引,也就是無(wú)法優(yōu)化……
使用SQL語(yǔ)句時(shí)應(yīng)注意以下幾點(diǎn):
1、避免使用不兼容的數(shù)據(jù)類型。例如,F(xiàn)loat和Integer,Char和Varchar,Binary和LongBinary不兼容的。數(shù)據(jù)類型的不兼容可能使優(yōu)化器無(wú)法執(zhí)行一些本可以進(jìn)行的優(yōu)化操作。例如:
selectemp_nameformemployeewheresalary>3000;
在此語(yǔ)句中若salary是Float類型的,則優(yōu)化器很難對(duì)其進(jìn)行優(yōu)化,因?yàn)?000是個(gè)整數(shù),我們應(yīng)在編程時(shí)使用3000.0而不要等運(yùn)行時(shí)讓DBMS進(jìn)行轉(zhuǎn)化。
2、盡量不要使用表達(dá)式,因它在編繹時(shí)是無(wú)法得到的,所以SQL只能使用其平均密度來(lái)估計(jì)將要命中的記錄數(shù)。
3、避免對(duì)搜索參數(shù)使用其他的數(shù)學(xué)操作符。如:
selectemp_namefromemployeewheresalary*12>3000;
應(yīng)改為:
selectemp_namefromemployeewheresalary>250;
4、避免使用!=或等這樣的操作符,因?yàn)樗鼤?huì)使系統(tǒng)無(wú)法使用索引,而只能直接搜索表中的數(shù)據(jù)。
·ORACAL中的應(yīng)用
一個(gè)1600萬(wàn)數(shù)據(jù)表--短信上行表TBL_SMS_MO
結(jié)構(gòu):
CREATETABLETBL_SMS_MO
(
SMS_IDNUMBER,
MO_IDVARCHAR2(50),
MOBILEVARCHAR2(11),
SPNUMBERVARCHAR2(20),
MESSAGEVARCHAR2(150),
TRADE_CODEVARCHAR2(20),
LINK_IDVARCHAR2(50),
GATEWAY_IDNUMBER,
GATEWAY_PORTNUMBER,
MO_TIMEDATEDEFAULTSYSDATE
);
CREATEINDEXIDX_MO_DATEONTBL_SMS_MO(MO_TIME)
PCTFREE10
INITRANS2
MAXTRANS255
STORAGE
(
INITIAL1M
NEXT1M
MINEXTENTS1
MAXEXTENTSUNLIMITED
PCTINCREASE0
);
CREATEINDEXIDX_MO_MOBILEONTBL_SMS_MO(MOBILE)
PCTFREE10
INITRANS2
MAXTRANS255
STORAGE
(
INITIAL64K
NEXT1M
MINEXTENTS1
MAXEXTENTSUNLIMITED
PCTINCREASE0
);
問(wèn)題:從表中查詢某時(shí)間段內(nèi)某手機(jī)發(fā)送的短消息,如下SQL語(yǔ)句:
SELECTMOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROMTBL_SMS_MO
WHEREMOBILE='130XXXXXXXX'
ANDMO_TIMEBETWEENTO_DATE('2006-04-01','YYYY-MM-DDHH24:MI:SS')ANDTO_DATE('2006-04-07','YYYY-MM-DDHH24:MI:SS')
ORDERBYMO_TIMEDESC
返回結(jié)果大約需要10分鐘,應(yīng)用于網(wǎng)頁(yè)查詢,簡(jiǎn)直難以忍受。
分析:
在PL/SQLDeveloper,點(diǎn)擊“ExplainPlan”按鈕(或F5鍵),對(duì)SQL進(jìn)行分析,發(fā)現(xiàn)缺省使用的索引是IDX_MO_DATE。問(wèn)題可能出在這里,因?yàn)橄鄬?duì)于總數(shù)量1600萬(wàn)數(shù)據(jù)來(lái)說(shuō),都mobile的數(shù)據(jù)是很少的,如果使用IDX_MO_MOBILE比較容易鎖定數(shù)據(jù)。
如下優(yōu)化:
SELECT/*+index(TBL_SMS_MOIDX_MO_MOBILE)*/MOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROMTBL_SMS_MO
WHEREMOBILE='130XXXXXXXX'
ANDMO_TIMEBETWEENTO_DATE('2006-04-01','YYYY-MM-DDHH24:MI:SS')ANDTO_DATE('2006-04-07','YYYY-MM-DDHH24:MI:SS')
ORDERBYMO_TIMEDESC
測(cè)試:
按F8運(yùn)行這個(gè)SQL,哇~......2.360s,這就是差別。
http://www.cnblogs.com/ShaYeBlog/archive/2013/07/31/3227244.html