《MYSQL數(shù)據(jù)庫(kù)Mysql查詢(xún)語(yǔ)句優(yōu)化技巧》要點(diǎn):
本文介紹了MYSQL數(shù)據(jù)庫(kù)Mysql查詢(xún)語(yǔ)句優(yōu)化技巧,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
索引優(yōu)化,查詢(xún)優(yōu)化,查詢(xún)緩存,服務(wù)器設(shè)置優(yōu)化,操作系統(tǒng)和硬件優(yōu)化,應(yīng)用層面優(yōu)化(web服務(wù)器,緩存)等等.這里的記錄的優(yōu)化技巧更適用于開(kāi)發(fā)人員,都是從網(wǎng)絡(luò)上收集和本身整理的,主要是查詢(xún)語(yǔ)句上面的優(yōu)化,其它層面的優(yōu)化技巧在此不做記錄.MYSQL數(shù)據(jù)庫(kù)
查詢(xún)的開(kāi)銷(xiāo)指標(biāo):MYSQL數(shù)據(jù)庫(kù)
執(zhí)行時(shí)間
MYSQL數(shù)據(jù)庫(kù)
檢查的行數(shù)
MYSQL數(shù)據(jù)庫(kù)
返回的行數(shù)MYSQL數(shù)據(jù)庫(kù)
建立索引的幾個(gè)準(zhǔn)則:MYSQL數(shù)據(jù)庫(kù)
(1)、合理的建立索引能夠加速數(shù)據(jù)讀取效率,不合理的建立索引反而會(huì)拖慢數(shù)據(jù)庫(kù)的響應(yīng)速度.
MYSQL數(shù)據(jù)庫(kù)
(2)、索引越多,更新數(shù)據(jù)的速度越慢.
MYSQL數(shù)據(jù)庫(kù)
(3)、盡量在采納MyIsam作為引擎的時(shí)候使用索引(因?yàn)镸ySQL以BTree存儲(chǔ)索引),而不是InnoDB.但MyISAM不支持MYSQL數(shù)據(jù)庫(kù)
Transcation.
MYSQL數(shù)據(jù)庫(kù)
(4)、當(dāng)你的程序和數(shù)據(jù)庫(kù)結(jié)構(gòu)/SQL語(yǔ)句已經(jīng)優(yōu)化到無(wú)法優(yōu)化的程度,而程序瓶頸并不能順利辦理,那就是應(yīng)該考慮使用諸如memcached這樣的分布式緩存系統(tǒng)的時(shí)候了.
MYSQL數(shù)據(jù)庫(kù)
(5)、習(xí)慣和強(qiáng)迫本身用EXPLAIN來(lái)分析你SQL語(yǔ)句的性能.MYSQL數(shù)據(jù)庫(kù)
一、count的優(yōu)化MYSQL數(shù)據(jù)庫(kù)
好比:計(jì)算id大于5的城市MYSQL數(shù)據(jù)庫(kù)
select count(*) from world.city where id > ; select (select count() from world.city) C count() from world.city where id <= ;
a語(yǔ)句當(dāng)行數(shù)超過(guò)11行的時(shí)候必要掃描的行數(shù)比b語(yǔ)句要多, b語(yǔ)句掃描了6行,此種情況下,b語(yǔ)句比a語(yǔ)句更有效率.當(dāng)沒(méi)有where語(yǔ)句的時(shí)候直接select count(*) from world.city這樣會(huì)更快,因?yàn)閙ysql總是知道表的行數(shù).MYSQL數(shù)據(jù)庫(kù)
二、避免使用不兼容的數(shù)據(jù)類(lèi)型MYSQL數(shù)據(jù)庫(kù)
例如float和int、char和varchar、binary和varbinary是不兼容的.數(shù)據(jù)類(lèi)型的不兼容可能使優(yōu)化器無(wú)法執(zhí)行一些原來(lái)可以進(jìn)行的優(yōu)化操作.MYSQL數(shù)據(jù)庫(kù)
在程序中,保證在實(shí)現(xiàn)功能的基礎(chǔ)上,盡量減少對(duì)數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn)次數(shù);通過(guò)搜索參數(shù),盡量減少對(duì)表的訪(fǎng)問(wèn)行數(shù),最小化結(jié)果集,從而減輕網(wǎng)絡(luò)負(fù)擔(dān);能夠分開(kāi)的操作盡量分開(kāi)處理,提高每次的響應(yīng)速度;在數(shù)據(jù)窗口使用SQL時(shí),盡量把使用的索引放在選擇的首列;算法的結(jié)構(gòu)盡量簡(jiǎn)單;在查詢(xún)時(shí),不要過(guò)多地使用通配符如 SELECT * FROM T1語(yǔ)句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的情況下盡量限制盡量結(jié)果集行數(shù)如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因?yàn)槟承┣闆r下用戶(hù)是不需要那么多的數(shù)據(jù)的.不要在應(yīng)用中使用數(shù)據(jù)庫(kù)游標(biāo),游標(biāo)是非常有用的工具,但比使用常規(guī)的、面向集的SQL語(yǔ)句需要更大的開(kāi)銷(xiāo);依照特定順序提取數(shù)據(jù)的查找.MYSQL數(shù)據(jù)庫(kù)
三、索引字段上進(jìn)行運(yùn)算會(huì)使索引失效MYSQL數(shù)據(jù)庫(kù)
盡量避免在WHERE子句中對(duì)字段進(jìn)行函數(shù)或表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描.如:MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM T1 WHERE F1/2=100 應(yīng)改為: SELECT * FROM T1 WHERE F1=100*2
四、避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符MYSQL數(shù)據(jù)庫(kù)
因?yàn)檫@會(huì)使系統(tǒng)無(wú)法使用索引,而只能直接搜索表中的數(shù)據(jù).例如: SELECT id FROM employee WHERE id != “B%” 優(yōu)化器將無(wú)法通過(guò)索引來(lái)確定將要命中的行數(shù),因此必要搜索該表的所有行.在in語(yǔ)句中能用exists語(yǔ)句代替的就用exists.MYSQL數(shù)據(jù)庫(kù)
五、盡量使用數(shù)字型字段MYSQL數(shù)據(jù)庫(kù)
一部分開(kāi)發(fā)人員和數(shù)據(jù)庫(kù)管理人員喜歡把包括數(shù)值信息的字段MYSQL數(shù)據(jù)庫(kù)
設(shè)計(jì)為字符型,這會(huì)降低查詢(xún)和連接的性能,并會(huì)增加存儲(chǔ)開(kāi)銷(xiāo).這是因?yàn)橐嬖谔幚聿樵?xún)和連接回逐個(gè)比擬字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比擬一次就夠了.MYSQL數(shù)據(jù)庫(kù)
六、合理使用EXISTS,NOT EXISTS子句MYSQL數(shù)據(jù)庫(kù)
如下所示:MYSQL數(shù)據(jù)庫(kù)
SELECT SUM(T1.C1) FROM T1 WHERE (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FROM T2 WHERE T2.C2=T1.C2)
兩者產(chǎn)生相同的結(jié)果,但是后者的效率顯然要高于前者.因?yàn)楹笳卟粫?huì)產(chǎn)生大量鎖定的表掃描或是索引掃描.如果你想校驗(yàn)內(nèi)外是否存在某條紀(jì)錄,不要用count(*)那樣效率很低,而且浪費(fèi)服務(wù)器資源.可以用EXISTS代替.如:MYSQL數(shù)據(jù)庫(kù)
IF (SELECT COUNT() FROM table_name WHERE column_name = ‘xxx')可以寫(xiě)成:IF EXISTS (SELECT FROM table_name WHERE column_name = ‘xxx')
七、 能夠用BETWEEN的就不要用INMYSQL數(shù)據(jù)庫(kù)
八、 能夠用DISTINCT的就不消GROUP BYMYSQL數(shù)據(jù)庫(kù)
九、盡量不要用SELECT INTO語(yǔ)句.MYSQL數(shù)據(jù)庫(kù)
SELECT INTO 語(yǔ)句會(huì)導(dǎo)致表鎖定,阻止其他用戶(hù)拜訪(fǎng)該表MYSQL數(shù)據(jù)庫(kù)
十、 需要時(shí)強(qiáng)制查詢(xún)優(yōu)化器使用某個(gè)索引MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM T1 WHERE nextprocess = 1 AND processid IN (8,32,45) 改成: SELECT * FROM T1 (INDEX = IX_ProcessID) WHERE nextprocess = 1 AND processid IN (8,32,45)
則查詢(xún)優(yōu)化器將會(huì)強(qiáng)行利用索引IX_ProcessID 執(zhí)行查詢(xún).MYSQL數(shù)據(jù)庫(kù)
十一、消除對(duì)大型表行數(shù)據(jù)的順序存取MYSQL數(shù)據(jù)庫(kù)
盡管在所有的檢查列上都有索引,但某些形式的WHERE子句逼迫優(yōu)化器使用順序存取.如:MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
解決方法可以使用并集來(lái)避免順序存取:MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 UNION SELECT * FROM orders WHERE order_num=1008
這樣就能利用索引路徑處理查詢(xún).【jacking 數(shù)據(jù)成果集很多,但查詢(xún)條件限定后成果集不大的情況下,后面的語(yǔ)句快】MYSQL數(shù)據(jù)庫(kù)
十二、盡量避免在索引過(guò)的字符數(shù)據(jù)中,使用非打頭字母搜索.MYSQL數(shù)據(jù)庫(kù)
這也使得引擎無(wú)法利用索引MYSQL數(shù)據(jù)庫(kù)
見(jiàn)如下例子:MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM T1 WHERE NAME LIKE ‘%L%' SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)='L' SELECT * FROM T1 WHERE NAME LIKE ‘L%'
即使NAME字段建有索引,前兩個(gè)查詢(xún)依然無(wú)法利用索引完成加快操作,引擎不得紕謬全表所有數(shù)據(jù)逐條操作來(lái)完成任務(wù).而第三個(gè)查詢(xún)能夠使用索引來(lái)加快操作,不要習(xí)慣性的使用 ‘%L%'這種方式(會(huì)導(dǎo)致全表掃描),如果可以使用`L%'相對(duì)來(lái)說(shuō)更好;MYSQL數(shù)據(jù)庫(kù)
十三、雖然UPDATE、DELETE語(yǔ)句的寫(xiě)法基本固定,但是還是對(duì)UPDATE語(yǔ)句給點(diǎn)建議MYSQL數(shù)據(jù)庫(kù)
(1). 盡量不要修改主鍵字段.
MYSQL數(shù)據(jù)庫(kù)
(2). 當(dāng)修改VARCHAR型字段時(shí),盡量使用相同長(zhǎng)度內(nèi)容的值代替.
MYSQL數(shù)據(jù)庫(kù)
(3). 盡量最小化對(duì)于含有UPDATE觸發(fā)器的表的UPDATE操作.
MYSQL數(shù)據(jù)庫(kù)
(4). 避免UPDATE將要復(fù)制到其他數(shù)據(jù)庫(kù)的列.
MYSQL數(shù)據(jù)庫(kù)
(5). 避免UPDATE建有很多索引的列.
MYSQL數(shù)據(jù)庫(kù)
(6). 避免UPDATE在WHERE子句條件中的列.MYSQL數(shù)據(jù)庫(kù)
十四、能用UNION ALL就不要用UNIONMYSQL數(shù)據(jù)庫(kù)
UNION ALL不執(zhí)行SELECT DISTINCT函數(shù),這樣就會(huì)減少很多不需要的資源MYSQL數(shù)據(jù)庫(kù)
在跨多個(gè)不同的數(shù)據(jù)庫(kù)時(shí)使用UNION是一個(gè)有趣的優(yōu)化辦法,UNION從兩個(gè)互不關(guān)聯(lián)的表中返回?cái)?shù)據(jù),這就意味著不會(huì)出現(xiàn)重復(fù)的行,同時(shí)也必須對(duì)數(shù)據(jù)進(jìn)行排序,我們知道排序是非常耗費(fèi)資源的,特別是對(duì)大表的排序.MYSQL數(shù)據(jù)庫(kù)
UNION ALL可以大大加快速度,如果你已經(jīng)知道你的數(shù)據(jù)不會(huì)包括重復(fù)行,或者你不在乎是否會(huì)出現(xiàn)重復(fù)的行,在這兩種情況下使用UNION ALL更適合.此外,還可以在應(yīng)用程序邏輯中采用某些辦法避免出現(xiàn)重復(fù)的行,這樣UNION ALL和UNION返回的結(jié)果都是一樣的,但UNION ALL不會(huì)進(jìn)行排序.MYSQL數(shù)據(jù)庫(kù)
十五、字段數(shù)據(jù)類(lèi)型優(yōu)化MYSQL數(shù)據(jù)庫(kù)
(1). 避免使用NULL類(lèi)型:NULL對(duì)于大多數(shù)數(shù)據(jù)庫(kù)都必要特殊處理,MySQL也不例外,它必要更多的代碼,更多的檢查和特殊的索引邏輯,有些開(kāi)發(fā)人員完全沒(méi)有意識(shí)到,創(chuàng)建表時(shí)NULL是默認(rèn)值,但大多數(shù)時(shí)候應(yīng)該使用NOT NULL,或者使用一個(gè)特殊的值,如0,-1作為默認(rèn)值.MYSQL數(shù)據(jù)庫(kù)
(2). 盡可能使用更小的字段,MySQL從磁盤(pán)讀取數(shù)據(jù)后是存儲(chǔ)到內(nèi)存中的,然后使用cpu周期和磁盤(pán)I/O讀取它,這意味著越小的數(shù)據(jù)類(lèi)型占用的空間越小,從磁盤(pán)讀或打包到內(nèi)存的效率都更好,但也不要太過(guò)執(zhí)著減小數(shù)據(jù)類(lèi)型,要是以后應(yīng)用程序發(fā)生什么變化就沒(méi)有空間了.修改表將必要重構(gòu),間接地可能引起代碼的改變,這是很頭疼的問(wèn)題,因此必要找到一個(gè)平衡點(diǎn).MYSQL數(shù)據(jù)庫(kù)
(3). 優(yōu)先使用定長(zhǎng)型MYSQL數(shù)據(jù)庫(kù)
十七、關(guān)于大數(shù)據(jù)量limit分布的優(yōu)化(當(dāng)偏移量特別大時(shí),limit效率會(huì)非常低)MYSQL數(shù)據(jù)庫(kù)
附上一個(gè)提高limit效率的簡(jiǎn)單技巧,在覆蓋索引(覆蓋索引用通俗的話(huà)講就是在select的時(shí)候只用去讀取索引而取得數(shù)據(jù),無(wú)需進(jìn)行二次select相關(guān)表)上進(jìn)行偏移,而不是對(duì)全行數(shù)據(jù)進(jìn)行偏移.可以將從覆蓋索引上提取出來(lái)的數(shù)據(jù)和全行數(shù)據(jù)進(jìn)行聯(lián)接,然后取得必要的列,會(huì)更有效率,看看下面的查詢(xún):MYSQL數(shù)據(jù)庫(kù)
mysql> select film_id, description from sakila.film order by title limit 50, 5;
如果表非常大,這個(gè)查詢(xún)最好寫(xiě)成下面的樣子:MYSQL數(shù)據(jù)庫(kù)
mysql> select film.film_id, film.description from sakila.film inner join(select film_id from sakila.film order by title liimit 50,5) as film usinig(film_id);
十八、法式中如果一次性對(duì)同一個(gè)表插入多條數(shù)據(jù)MYSQL數(shù)據(jù)庫(kù)
好比以下語(yǔ)句:MYSQL數(shù)據(jù)庫(kù)
insert into person(name,age) values(‘xboy', 14); insert into person(name,age) values(‘xgirl', 15); insert into person(name,age) values(‘nia', 19);
把它拼成一條語(yǔ)句執(zhí)行效率會(huì)更高.MYSQL數(shù)據(jù)庫(kù)
insert into person(name,age) values(‘xboy', 14), (‘xgirl', 15),(‘nia', 19);
十九、不要在選擇的欄位上放置索引,這是無(wú)意義的.MYSQL數(shù)據(jù)庫(kù)
應(yīng)該在條件選擇的語(yǔ)句上合理的放置索引,好比where,order byMYSQL數(shù)據(jù)庫(kù)
SELECT id,title,content,cat_id FROM article WHERE cat_id = 1;
上面這個(gè)語(yǔ)句,你在id/title/content上放置索引是毫無(wú)意義的,對(duì)這個(gè)語(yǔ)句沒(méi)有任何優(yōu)化作用.但是如果你在外鍵cat_id上放置一個(gè)索引,那作用就相當(dāng)大了.MYSQL數(shù)據(jù)庫(kù)
二十、ORDER BY語(yǔ)句的MySQL優(yōu)化MYSQL數(shù)據(jù)庫(kù)
(1). ORDER BY + LIMIT組合的索引優(yōu)化.如果一個(gè)SQL語(yǔ)句形如:MYSQL數(shù)據(jù)庫(kù)
SELECT [column1],[column2],…. FROM [TABLE] ORDER BY [sort] LIMIT [offset],[LIMIT];
這個(gè)SQL語(yǔ)句優(yōu)化比擬簡(jiǎn)單,在[sort]這個(gè)欄位上建立索引即可.MYSQL數(shù)據(jù)庫(kù)
(2). WHERE + ORDER BY + LIMIT組合的索引優(yōu)化,形如:MYSQL數(shù)據(jù)庫(kù)
SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] = [VALUE] ORDER BY [sort] LIMIT [offset],[LIMIT];
這個(gè)語(yǔ)句,如果你仍然采用第一個(gè)例子中建立索引的辦法,雖然可以用到索引,但是效率不高.更高效的辦法是建立一個(gè)聯(lián)合索引(columnX,sort)MYSQL數(shù)據(jù)庫(kù)
(3). WHERE + IN + ORDER BY + LIMIT組合的索引優(yōu)化,形如:MYSQL數(shù)據(jù)庫(kù)
SELECT [column1],[column2],…. FROM [TABLE] WHERE [columnX] IN ([value1],[value2],…) ORDER BY [sort] LIMIT [offset],[LIMIT];
這個(gè)語(yǔ)句如果你采用第二個(gè)例子中建立索引的辦法,會(huì)得不到預(yù)期的效果(僅在[sort]上是using index,WHERE那里是using where;using filesort),理由是這里對(duì)應(yīng)columnX的值對(duì)應(yīng)多個(gè).MYSQL數(shù)據(jù)庫(kù)
目前哥還木有找到比較優(yōu)秀的方法,等待高手指教.MYSQL數(shù)據(jù)庫(kù)
(4).WHERE+ORDER BY多個(gè)欄位+LIMIT,好比:MYSQL數(shù)據(jù)庫(kù)
SELECT * FROM [table] WHERE uid=1 ORDER x,y LIMIT 0,10;
對(duì)于這個(gè)語(yǔ)句,大家可能是加一個(gè)這樣的索引:(x,y,uid).但實(shí)際上更好的效果是(uid,x,y).這是由MySQL處置排序的機(jī)制造成的.MYSQL數(shù)據(jù)庫(kù)
《MYSQL數(shù)據(jù)庫(kù)Mysql查詢(xún)語(yǔ)句優(yōu)化技巧》是否對(duì)您有啟發(fā),歡迎查看更多與《MYSQL數(shù)據(jù)庫(kù)Mysql查詢(xún)語(yǔ)句優(yōu)化技巧》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/12353.html