MySQL索引的創建對於MySQL的高效運行是很重要的,索引能夠大大提升MySQL的檢索速度。mysql
1.實際上,索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄。sql
2.索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表能夠有多個單列索引,但這不 是組合索引。組合索引,即一個索引包含多個列。函數
3.普通索引性能
建立索引:最基本的索引,它沒有任何限制。它有如下幾種建立方式:大數據
3.一、優化
CREATE INDEX indexName ON mytable(username(length));
若是是CHAR,VARCHAR類型,length能夠小於字段實際長度;若是是BLOB和TEXT類型,必須指定 length。spa
3.二、修改表結構添加索引.net
ALTER table tableName ADD INDEX indexName(columnName)
3.三、建立表的時候直接指定unix
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName](username(length)));
4.惟一索引code
它與前面的普通索引相似,不一樣的就是:索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須惟一。UNIQUE 修飾索引便可;建立略;
一、最左前綴匹配原則,聯合索引,mysql會從作向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
二、=和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式。
三、索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’)。
四、儘可能的擴展索引,不要新建索引。好比表中已經有a的索引,如今要加(a,b)的索引,那麼只須要修改原來的索引便可,創建沒必要要索引會增長MySQL空間。
五、儘可能選擇區分度高的列做爲索引 區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定,通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄。
六、若是肯定有多少條數據,使用 limit 限制一下,MySQL在查找到對應條數的數據的時候,會中止繼續查找。
七、join 語法,儘可能將小的表放在前面,在須要on的字段上,數據類型保持一致,並設置對應的索引,不然MySQL沒法使用索引來join查詢
使用explain關鍵字能夠模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的,分析你的查詢語句或是表結構的性能瓶頸。
Explain包含信息
其中最重要的字段爲:id、type、key、rows、Extra
Id表示查詢中執行select字句或者操做表順序
Id相同:執行順序由上至下
id不一樣:若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
查詢的類型,主要是用於區分普通查詢、聯合查詢、子查詢等複雜的查詢
一、SIMPLE:簡單的select查詢,查詢中不包含子查詢或者union
二、PRIMARY:查詢中包含任何複雜的子部分,最外層查詢則被標記爲primary
三、SUBQUERY:在select 或 where列表中包含了子查詢
四、DERIVED:在from列表中包含的子查詢被標記爲derived(衍生),mysql或遞歸執行這些子查詢,把結果放在零時表裏
五、UNION:若第二個select出如今union以後,則被標記爲union;若union包含在from子句的子查詢中,外層select將被標記爲derived
六、UNION RESULT:從union表獲取結果的select
訪問類型,sql查詢優化中一個很重要的指標,結果值從好到壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL;
通常來講,好的sql查詢至少達到range級別,最好能達到ref
一、system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,能夠忽略不計
二、const:表示經過索引一次就找到了,const用於比較primary key 或者 unique索引。由於只需匹配一行數據,全部很快。若是將主鍵置於where列表中,mysql就能將該查詢轉換爲一個const
三、eq_ref:惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵 或 惟一索引掃描
四、ref:非惟一性索引掃描,返回匹配某個單獨值的全部行。本質是也是一種索引訪問,它返回全部匹配某個單獨值的行,然而他可能會找到多個符合條件的行,因此它應該屬於查找和掃描的混合體
五、range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了那個索引。通常就是在where語句中出現了bettween、<、>、in等的查詢。這種索引列上的範圍掃描比全索引掃描要好。只須要開始於某個點,結束於另外一個點,不用掃描所有索引
六、index:Full Index Scan,index與ALL區別爲index類型只遍歷索引樹。這一般爲ALL塊,應爲索引文件一般比數據文件小。(Index與ALL雖然都是讀全表,但index是從索引中讀取,而ALL是從硬盤讀取)
七、ALL:Full Table Scan,遍歷全表以找到匹配的行
查詢涉及到的字段上存在索引,則該索引將被列出,但不必定被查詢實際使用;
key
實際使用的索引,若是爲NULL,則沒有使用索引。
查詢中若是使用了覆蓋索引,則該索引僅出如今key列表中
ref
顯示索引的那一列被使用了,若是可能,是一個常量const。
1.對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。
2.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢:
select id from t where num=0
3.應儘可能避免在 where 子句中使用!=或<>操做符,不然引擎將放棄使用索引而進行全表掃描
4.應儘可能避免在 where 子句中使用or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描,如:
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 也要慎用,不然會致使全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查詢也將致使全表掃描:select id from t where name like ‘%李%’若要提升效率,能夠考慮全文檢索
7. 若是在 where 子句中使用參數,也會致使全表掃描。由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。以下面語句將進行全表掃描:select id from t where num=@num能夠改成強制查詢使用索引:select id from t with(index(索引名)) where num=@num
8.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如:select id from t where num/2=100應改成:select id from t where num=100*2
9.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)=’abc’
,name以abc開頭的id應改成:
select id from t where name like ‘abc%’
10.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
11.在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使用,而且應儘量的讓字段順序與索引順序相一致。
12.不要寫一些沒有意義的查詢,如須要生成一個空表結構:select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,可是會消耗系統資源的,應改爲這樣:
create table #t(…)
13.不少時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
14.並非全部索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那麼即便在sex上建了索引也對查詢效率起不了做用。
20.儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。
21.避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。
22.在新建臨時表時,若是一次性插入數據量很大,那麼可使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。
23.若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定。