原文鏈接:mysql建立索引的幾大原則 - Cheney.rain - 博客園
mysql中建立索引的一些原則 - szllq2000 - 博客園
1.選擇唯一性索引
唯一性索引的值是唯一的,可以更快速的通過該索引來(lái)確定某條記錄。例如,學(xué)生表中學(xué)號(hào)是具有唯一性的字段。為該字段建立唯一性索引可以很快的確定某個(gè)學(xué)生的信息。如果使用姓名的話,可能存在同名現(xiàn)象,從而降低查詢速度。
2.為經(jīng)常需要排序、分組和聯(lián)合操作的字段建立索引
經(jīng)常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作會(huì)浪費(fèi)很多時(shí)間。如果為其建立索引,可以有效地避免排序操作。
3.為常作為查詢條件的字段建立索引
如果某個(gè)字段經(jīng)常用來(lái)做查詢條件,那么該字段的查詢速度會(huì)影響整個(gè)表的查詢速度。因此,為這樣的字段建立索引,可以提高整個(gè)表的查詢速度。
4.限制索引的數(shù)目
索引的數(shù)目不是越多越好。每個(gè)索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大。修改表時(shí),對(duì)索引的重構(gòu)和更新很麻煩。越多的索引,會(huì)使更新表變得很浪費(fèi)時(shí)間。
5.盡量使用數(shù)據(jù)量少的索引
如果索引的值很長(zhǎng),那么查詢的速度會(huì)受到影響。例如,對(duì)一個(gè)CHAR(100)類型的字段進(jìn)行全文檢索需要的時(shí)間肯定要比對(duì)CHAR(10)類型的字段需要的時(shí)間要多。
6.盡量使用前綴來(lái)索引
如果索引字段的值很長(zhǎng),最好使用值的前綴來(lái)索引。例如,TEXT和BLOG類型的字段,進(jìn)行全文檢索會(huì)很浪費(fèi)時(shí)間。如果只檢索字段的前面的若干個(gè)字符,這樣可以提高檢索速度。
7.刪除不再使用或者很少使用的索引
表中的數(shù)據(jù)被大量更新,或者數(shù)據(jù)的使用方式被改變后,原有的一些索引可能不再需要。數(shù)據(jù)庫(kù)管理員應(yīng)當(dāng)定期找出這些索引,將它們刪除,從而減少索引對(duì)更新操作的影響。
8 . 最左前綴匹配原則,非常重要的原則。
mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a 1=”” and=”” b=”2” c=”“> 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。
9 .=和in可以亂序。
比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優(yōu)化器會(huì)幫你優(yōu)化成索引可以識(shí)別的形式
10 . 盡量選擇區(qū)分度高的列作為索引。
區(qū)分度的公式是count(distinct col)/count(*),表示字段不重復(fù)的比例,比例越大我們掃描的記錄數(shù)越少,唯一鍵的區(qū)分度是1,而一些狀態(tài)、性別字段可能在大數(shù)據(jù)面前區(qū)分度就 是0,那可能有人會(huì)問,這個(gè)比例有什么經(jīng)驗(yàn)值嗎?使用場(chǎng)景不同,這個(gè)值也很難確定,一般需要join的字段我們都要求是0.1以上,即平均1條掃描10條 記錄
11 .索引列不能參與計(jì)算,保持列“干凈”。
比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡(jiǎn)單,b+樹中存的都是數(shù)據(jù)表中的字段值,但進(jìn)行檢索時(shí),需要把所有元素都應(yīng)用函數(shù)才能比較,顯然成本 太大。所以語(yǔ)句應(yīng)該寫成create_time = unix_timestamp(’2014-05-29’);
12 .盡量的擴(kuò)展索引,不要新建索引。
比如表中已經(jīng)有a的索引,現(xiàn)在要加(a,b)的索引,那么只需要修改原來(lái)的索引即可
13、當(dāng)單個(gè)索引字段查詢數(shù)據(jù)很多,區(qū)分度都不是很大時(shí),則需要考慮建立聯(lián)合索引來(lái)提高查詢效率
注意:選擇索引的最終目的是為了使查詢的速度變快。上面給出的原則是最基本的準(zhǔn)則,但不能拘泥于上面的準(zhǔn)則。讀者要在以后的學(xué)習(xí)和工作中進(jìn)行不斷的實(shí)踐。根據(jù)應(yīng)用的實(shí)際情況進(jìn)行分析和判斷,選擇最合適的索引方式。
標(biāo)準(zhǔn)sql執(zhí)行順序

二
1、先存數(shù)據(jù),再建索引
有索引的好處是搜索比較快但是在有索引的前提下進(jìn)行插入、更新操作會(huì)很慢
2、不要對(duì)規(guī)模小的數(shù)據(jù)表建立索引,數(shù)據(jù)量超過300的表應(yīng)該有索引;
對(duì)于規(guī)模小的數(shù)據(jù)表建立索引 不僅不會(huì)提高功能,相反使用索引查找可能比簡(jiǎn)單的全表掃描還要嫚而且建索引還會(huì)占用一部分的存儲(chǔ)空間
3、當(dāng)對(duì)表的查詢操作比更新操作頻率更高時(shí),對(duì)該表建立索引
4、在不同值較少的字段上不必要建立索引,如性別字段
5、對(duì)于查詢操作中頻繁使用的列建立索引,不對(duì)很少或從來(lái)不作為查詢條件的列建立索引
6、表的主鍵、外鍵必須有索引;
7、經(jīng)常出現(xiàn)在Where子句中的字段,特別是大表的字段,應(yīng)該建立索引;
8、索引應(yīng)該建在選擇性高的字段上;在SQL語(yǔ)句中經(jīng)常進(jìn)行GROUP BY、ORDER BY的字段上建立索引;
9、索引應(yīng)該建在小字段上,對(duì)于大的文本字段甚至超長(zhǎng)字段,不要建索引
------------------------------------分割線------------------------------------------------
【避免全表掃描的方法】
1.對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
2.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,
如:select id from t where num is null可以在num上設(shè)置默認(rèn)值0,確保表中num列沒有null值,然后這樣查詢:select id from t where num=0
3.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則引擎將放棄使用索引而進(jìn)行全表掃描。
4.應(yīng)盡量避免在 where 子句中使用or 來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,
如:select id from t where num=10 or num=20可以這樣查詢:select id from t where num=10 union all select id from t where num=20
5.in?和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描,
如:select id from t where num in(1,2,3) 對(duì)于連續(xù)的數(shù)值,能用 between 就不要用 in 了:select id from t where num between 1 and 3
6.下面的查詢也將導(dǎo)致全表掃描:select id from t where name like '李%'若要提高效率,可以考慮全文檢索。
7..避免在索引列上使用計(jì)算,也就是說(shuō),應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作和函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。
如:select id from t where num/2=100應(yīng)改為:select id from t where num=100*2
select id from t where substring(name,1,3)='abc' ,name以abc開頭的id,應(yīng)改為:select id from t where name like 'abc%'
8.很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:exists用于檢查子查詢是否至少會(huì)返回一行數(shù)據(jù),該子查詢實(shí)際上并不返回任何數(shù)據(jù),而是返回值true或false。
select num from a where num in(select num from b)
用下面的語(yǔ)句替換:select num from a where exists (select 1 from b where num=a.num)
9.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
10.用>=替代>
高效: SELECT * FROM EMP WHERE DEPTNO >=4
低效: SELECT * FROM EMP WHERE DEPTNO >3
兩者的區(qū)別在于, 前者DBMS將直接跳到第一個(gè)DEPT等于4的記錄,而后者將首先定位到DEPTNO=3的記錄并且向前掃描到第一個(gè)DEPT大于3的記錄。
11.用Where子句替換having子句
------------------------------------分割線------------------------------------------------
【注意】
1.并不是所有索引對(duì)查詢都有效,SQL是根據(jù)表中數(shù)據(jù)來(lái)進(jìn)行查詢優(yōu)化的,當(dāng)索引列有大量數(shù)據(jù)重復(fù)時(shí),SQL查詢可能不會(huì)去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對(duì)查詢效率起不了作用。
2. 索引并不是越多越好,索引固然可 以提高相應(yīng)的 select 的效率,但同時(shí)也降低了 insert 及 update 的效率,因?yàn)?insert 或 update 時(shí)有可能會(huì)重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個(gè)表的索引數(shù)最好不要超過6個(gè),若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有 必要。
3.盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型,這會(huì)降低查詢和連接的性能,并會(huì)增加存儲(chǔ)開銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接時(shí)會(huì)逐個(gè)比較字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比較一次就夠了。
4.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因?yàn)槭紫茸冮L(zhǎng)字段存儲(chǔ)空間小,可以節(jié)省存儲(chǔ)空間,其次對(duì)于查詢來(lái)說(shuō),在一個(gè)相對(duì)較小的字段內(nèi)搜索效率顯然要高些。
5.避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。
6.在新建臨時(shí)表時(shí),如果一次性插入數(shù)據(jù)量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create table,然后insert。
7.如果使用到了臨時(shí)表,在存儲(chǔ)過程的最后務(wù)必將所有的臨時(shí)表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統(tǒng)表的較長(zhǎng)時(shí)間鎖定。
8.盡量避免使用游標(biāo),因?yàn)橛螛?biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過1萬(wàn)行,那么就應(yīng)該考慮改寫。
9.在所有的存儲(chǔ)過程和觸發(fā)器的開始處設(shè)置 SET NOCOUNT ON ,在結(jié)束時(shí)設(shè)置 SET NOCOUNT OFF 。無(wú)需在執(zhí)行存儲(chǔ)過程和觸發(fā)器的每個(gè)語(yǔ)句后向客戶端發(fā)送DONE_IN_PROC 消息。
10.盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。
11.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應(yīng)該考慮相應(yīng)需求是否合理。