MYsql高并發(fā)查詢優(yōu)化 文檔_第1頁
MYsql高并發(fā)查詢優(yōu)化 文檔_第2頁
MYsql高并發(fā)查詢優(yōu)化 文檔_第3頁
MYsql高并發(fā)查詢優(yōu)化 文檔_第4頁
MYsql高并發(fā)查詢優(yōu)化 文檔_第5頁
已閱讀5頁,還剩2頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

MYsql高并發(fā)查詢優(yōu)化方案總體原則:1)索引!索引!索引!數(shù)據(jù)表中,盡量建立主鍵。如果是where條件,必須加索引!2) 盡量減少對數(shù)據(jù)庫的訪問次數(shù),可以用緩存保存查詢結(jié)果,減少查詢次數(shù));3) 通過搜索參數(shù),盡量減少對表的訪問行數(shù),最小化結(jié)果集,從而減輕網(wǎng)絡(luò)負擔(dān);4) 能夠分開的操作盡量分開處理,提高每次的響應(yīng)速度;5) 算法的結(jié)構(gòu)盡量簡單;6) Explain你的sql語句看看執(zhí)行效率低的是什么具體要注意的:應(yīng)盡量避免在where子句中對字段進行null值判斷,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,如:selectidfromtwherenumisnull可以在num上設(shè)置默認值0,確保表中num列沒有null值,然后這樣查詢:selectidfromtwherenum=0應(yīng)盡量避免在where子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。優(yōu)化器將無法通過索引來確定將要命中的行數(shù),因此需要搜索該表的所有行。應(yīng)盡量避免在where子句中使用or來連接條件,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,如:selectidfromtwherenum=10ornum=20可以這樣查詢:selectidfromtwherenum=10unionallselectidfromtwherenum=204.in和notin也要慎用,因為IN會使系統(tǒng)無法使用索引,而只能直接搜索表中的數(shù)據(jù)。如:selectidfromtwherenumin(1,2,3)對于連續(xù)的數(shù)值,能用between就不要用in了:selectidfromtwherenumbetween1and3盡量避免在索引過的字符數(shù)據(jù)中,使用非打頭字母搜索。這也使得引擎無法利用索引。見如下例子:SELECT*FROMT1WHERENAMELIKE'%L%’SELECT*FROMT1WHERESUBSTING(NAME,2,1)='L'SELECT*FROMT1WHERENAMELIKE'L%'即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數(shù)據(jù)逐條操作來完成任務(wù)。而第三個查詢能夠使用索引來加快操作。必要時強制查詢優(yōu)化器使用某個索引,如在where子句中使用參數(shù),也會導(dǎo)致全表掃描。因為SQL只有在運行時才會解析局部變量,但優(yōu)化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:selectidfromtwherenum=@num可以改為強制查詢使用索引:selectidfromtwith(index(索弓|名))wherenum=@num應(yīng)盡量避免在where子句中對字段進行表達式操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描。如:SELECT*FROMT1WHEREF1/2=100應(yīng)改為:SELECT*FROMT1WHEREF1=100*2SELECT*FROMRECORDWHERESUBSTRING(CARD_NO,1,4)='5378'應(yīng)改為:SELECT*FROMRECORDWHERECARD_NOLIKE'5378%'SELECTmember_number,first_name,last_nameFROMmembersWHEREDATEDIFF(yy,datofbirth,GETDATE())>21應(yīng)改為:SELECTmember_number,first_name,last_nameFROMmembersWHEREdateofbirth<DATEADD(yy廣21,GETDATE())即:任何對列的操作都將導(dǎo)致表掃描,它包括數(shù)據(jù)庫函數(shù)、計算表達式等等,查詢時要盡可能將操作移至等號右邊。應(yīng)盡量避免在where子句中對字段進行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進行全表掃描。如:selectidfromtwheresubstring(name,1,3)='abc'--name以abc開頭的idselectidfromtwheredatediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id應(yīng)改為:selectidfromtwherenamelike'abc%'selectidfromtwherecreatedate>='2005-11-30'andcreatedate<'2005-12-1'不要在where子句中的''=”左邊進行函數(shù)、算術(shù)運算或其他表達式運算,否則系統(tǒng)將可能無法正確使用索引。在使用索引字段作為條件時,如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,否則該索引將不會被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。很多時候用exists是一個好的選擇:electnumfromawherenumin(selectnumfromb)用下面的語句替換:selectnumfromawhereexists(select1frombwherenum=a.num)SELECTSUM(T1.C1)FROMT1WHERE((SELECTCOUNT(*)FROMT2WHERET2.C2=T1.C2>0)SELECTSUM(T1.C1)FROMT1WHEREEXISTS(SELECT*FROMT2WHERET2.C2=T1.C2)兩者產(chǎn)生相同的結(jié)果,但是后者的效率顯然要高于前者。因為后者不會產(chǎn)生大量鎖定的表掃描或是索引掃描。如果你想校驗表里是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費服務(wù)器資源??梢杂肊XISTS代替。如:IF(SELECTCOUNT(*)FROMtable_nameWHEREcolumn_name='xxx')可以寫成:IFEXISTS(SELECT*FROMtable_nameWHEREcolumn_name='xxx')經(jīng)常需要寫一個T_SQL語句比較一個父結(jié)果集和子結(jié)果集,從而找到是否存在在父結(jié)果集中有而在子結(jié)果集中沒有的記錄,如:SELECTa.hdr_keyFROMhdr_tbla----tbla表示tbl用別名a代替WHERENOTEXISTS(SELECT*FROMdtl_tblbWHEREa.hdr_key=b.hdr_key)SELECTa.hdr_keyFROMhdr_tblaLEFTJOINdtl_tblbONa.hdr_key=b.hdr_keyWHEREb.hdr_keyISNULLSELECThdr_keyFROMhdr_tblWHEREhdr_keyNOTIN(SELECThdr_keyFROMdtl_tbl)三種寫法都可以得到同樣正確的結(jié)果,但是效率依次降低。盡量使用表變量來代替臨時表。如果表變量包含大量數(shù)據(jù),請注意索引非常有限(只有主鍵索引)。避免頻繁創(chuàng)建和刪除臨時表,以減少系統(tǒng)表資源的消耗。臨時表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行?,例如,?dāng)需要重復(fù)引用大型表或常用表中的某個數(shù)據(jù)集時。但是,對于一次性事件,最好使用導(dǎo)出表。在新建臨時表時,如果一次性插入數(shù)據(jù)量很大,那么可以使用selectinto代替createtable,避免造成大量log,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先createtable,然后inserto如果使用到了臨時表,在存儲過程的最后務(wù)必將所有的臨時表顯式刪除,先truncatetable,然后droptable,這樣可以避免系統(tǒng)表的較長時間鎖定。在所有的存儲過程和觸發(fā)器的開始處設(shè)置SETNOCOUNTON,在結(jié)束時設(shè)置SETNOCOUNTOFF。無需在執(zhí)行存儲過程和觸發(fā)器的每個語句后向客戶端發(fā)送DONE_IN_PROC消息。盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。19?盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應(yīng)該考慮相應(yīng)需求是否合理。20.避免使用不兼容的數(shù)據(jù)類型。例如float和int、char和varchar、binary和varbinary是不兼容的(條件判斷時)。數(shù)據(jù)類型的不兼容可能使優(yōu)化器無法執(zhí)行一些本來可以進行的優(yōu)化操作。例如:SELECTnameFROMemployeeWHEREsalary>60000在這條語句中,如salary字段是money型的,則優(yōu)化器很難對其進行優(yōu)化,因為60000是個整型數(shù)。我們應(yīng)當(dāng)在編程時將整型轉(zhuǎn)化成為錢幣型,而不要等到運行時轉(zhuǎn)化。充分利用連接條件(條件越多越快),在某種情況下,兩個表之間可能不只一個的連接條件,這時在WHERE子句中將連接條件完整的寫上,有可能大大提高查詢速度。例:SELECTSUM(A.AMOUNT)FROMACCOUNTA,CARDBWHEREA.CARD_NO=B.CARD_NOSELECTSUM(A.AMOUNT)FROMACCOUNTA,CARDBWHEREA.CARD_NO=B.CARD_NOANDA.ACCOUNT_NO=B.ACCOUNT_NO第二句將比第一句執(zhí)行快得多。22、 使用視圖加速查詢把表的一個子集進行排序并創(chuàng)建視圖,有時能加速查詢。它有助于避免多重排序操作,而且在其他方面還能簡化優(yōu)化器的工作。例如:SELECT,rcvbles.balance,othercolumnsFROMcust,rcvblesWHEREcust.customer_id=rcvlbes.customer_idANDrcvblls.balance>0ANDcust.postcode>''98000"ORDERBY如果這個查詢要被執(zhí)行多次而不止一次,可以把所有未付款的客戶找出來放在一個視圖中,并按客戶的名字進行排序:CREATEVIEWDBO.V_CUST_RCVLBESASSELECT,rcvbles.balance,othercolumnsFROMcust,rcvblesWHEREcust.customer_id=rcvlbes.customer_idANDrcvblls.balance>0ORDERBY然后以下面的方式在視圖中查詢:SELECT大FROMV_CUST_RCVLBESWHEREpostcode>“98000”視圖中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁盤I/O,所以查詢工作量可以得到大幅減少。能用DISTINCT的就不用GROUPBY(groupby操作特別慢)SELECTOrderIDFROMDetailsWHEREUnitPrice>10GROUPBYOrderID可改為:SELECTDISTINCTOrderIDFROMDetailsWHEREUnitPrice>10能用UNIONALL就不要用UNIONUNIONALL不執(zhí)行SELECTDISTINCT函數(shù),這樣就會減少很多不必要的資源盡量不要用SELECTINTO語句。SELECTINOT語句會導(dǎo)致表鎖定,阻止其他用戶訪問該表。上面我們提到的是一些基本的提高查詢速度的注意事項,但是在更多的情況下,往往需要反復(fù)試驗比較不同的語句以得到最佳方案。最好的方法當(dāng)然是測試,看實現(xiàn)相同功能的SQL語句哪個執(zhí)行

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論