索引
1.MySQL的三種存儲引擎
1.1InnoDB和MyISAM
InnoDB | MyISAM | |
---|---|---|
事務 | 支持 | 不支持 |
外鍵 | 支持 | 不支持 |
鎖 | 行級鎖、表級鎖,鎖定粒度小,併發能力高 | 表級鎖 |
文件格式 | 數據和索引集中存儲(.ibd);user.frm數據結構類型 | 數據和索引分開存儲,數據(.MYD),索引(.MYI);user.frm數據結構類型 |
應用場景 | 頻繁修改、涉及到安全性較高的應用 | 查詢以及插入爲主 |
B+樹索引 | 聚簇索引,葉子結點存儲行數據 | 非聚簇索引,葉子結點存儲行數據的地址 |
哈希索引 | 支持 | 不支持 |
全文索引 | 不支持 | 支持 |
1.2Memory
- MEMORY是MySQL中一類特殊的存儲引擎。它使用存儲在內存中的內容來創建表,而且數據全部放在內存中。
- 每個基於MEMORY存儲引擎的表實際對應一個磁盤文件。該文件中只存儲表的結構。而其數據文件,都是存儲在內存中,這樣有利於數據的快速處理,提高整個表的效率。
- 服務器需要有足夠的內存來維持MEMORY存儲引擎的表的使用。如果不需要了,可以釋放內存,甚至刪除不需要的表。
- MEMORY默認使用哈希索引。
2.索引
2.1什麼是索引
- 關鍵字與數據的映射關係稱爲索引(包含關鍵字和對應的記錄在磁盤中的地址)。關鍵字是從數據當中提取的用於標識、檢索數據的特定內容。
- 如果要查詢的字段都建立過索引,那麼引擎會直接在索引表中查詢而不會訪問原始數據(否則只要有一個字段沒有建立索引就會做全表掃描),這叫索引覆蓋。因此我們需要儘可能的在select後只寫必要的查詢字段,以增加索引覆蓋的機率。這裏值得注意的是不要想着爲每個字段建立索引,因爲優先使用索引的優勢就在於其體積小。
2.2索引檢索爲什麼快
- 關鍵字相對於數據本身,數據量小
- 關鍵字是有序的,二分查找可快速確定位置
2.3索引的幾種類型
- 主鍵索引: 數據列不允許重複,不允許爲NULL,一個表只能有一個主鍵。
- 唯一索引: 數據列不允許重複,允許爲NULL值,一個表允許多個列創建唯一索引。
- 普通索引: 基本的索引類型,沒有唯一性的限制,允許爲NULL值。
- 全文索引: 是目前搜索引擎使用的一種關鍵技術。
2.4索引的數據結構
- B+樹:
- 數據只在葉子結點,葉子結點有一條鏈相連。
- 非聚簇索引,MyISAM 引擎使用 B+Tree 作爲索引結構,葉節點的 data 域存放的是數據記錄的地址。在 MyISAM 中,主索引(也叫一級索引)和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求 key 是唯一的,而輔助索引的 key 可以重複。
- 而聚簇索引,data域即爲數據本身。輔助索引 data 域存儲相應記錄主鍵的值而不是地址。聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。
- 哈希索引:
- hash索引底層就是hash表,進行查找時,調用一次hash函數就可以獲取到相應的鍵值,之後進行回表查詢獲得實際數據。
- hash索引進行等值查詢更快(一般情況下),但是卻無法進行範圍查詢。
2.5創建索引的原則
- 索引雖好,但也不是無限制的使用,最好符合以下幾個原則
- 最左前綴匹配原則,組合索引非常重要的原則,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的順序可以任意調整。
- 較頻繁作爲查詢條件的字段纔去創建索引
- 更新頻繁字段不適合創建索引
- 若是不能有效區分數據的列不適合做索引列(如性別,男女未知,最多也就三種,區分度實在太低)
- 儘量的擴展索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可。
- 定義有外鍵的數據列一定要建立索引。
- 對於那些查詢中很少涉及的列,重複值比較多的列不要建立索引。
- 對於定義爲text、image和bit的數據類型的列不要建立索引。
3.MySQL優化方法
3.1選取最適用的字段屬性
-
MySQL可以很好的支持大數據量的存取,但是一般說來,數據庫中的表越小,在它上面執行的查詢也就會越快。因此,在創建表的時候,爲了獲得更好的性能,我們可以將表中字段的寬度設得儘可能小。
-
例如,在定義郵政編碼這個字段時,如果將其設置爲CHAR(255),顯然給數據庫增加了不必要的空間,甚至使用VARCHAR這種類型也是多餘的,因爲CHAR(6)就可以很好的完成任務了。同樣的,如果可以的話,我們應該使用MEDIUMINT而不是BIGIN來定義整型字段。
-
另外一個提高效率的方法是在可能的情況下,應該儘量把字段設置爲NOTNULL,這樣在將來執行查詢的時候,數據庫不用去比較NULL值。
-
對於某些文本字段,例如“省份”或者“性別”,我們可以將它們定義爲ENUM類型。因爲在MySQL中,ENUM類型被當作數值型數據來處理,而數值型數據被處理起來的速度要比文本類型快得多。這樣,我們又可以提高數據庫的性能。
3.2使用連接(JOIN)來代替子查詢(Sub-Queries)
- 因爲MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。
3.3使用聯合(UNION)來代替手動創建的臨時表
3.4使用事務
3.5鎖定表
-
LOCK TABLE inventory WRITE SELECT Quantity FROM inventory WHERE Item='book'; ... UPDATE inventory SET Quantity=11 WHERE Item='book'; UNLOCKTABLES
3.6使用外鍵
- 鎖定表的方法可以維護數據的完整性,但是它卻不能保證數據的關聯性。這個時候我們就可以使用外鍵。
3.7使用索引
- 對於查詢佔主要的應用來說,索引顯得尤爲重要。如果不加索引的話,那麼查找任何哪怕只是一條特定的數據都會進行一次全表掃描,如果一張表的數據量很大而符合條件的結果又很少,那麼不加索引會引起致命的性能下降。
- 但是也不是什麼情況都非得建索引不可,比如性別可能就只有兩個值,建索引不僅沒什麼優勢,還會影響到更新速度,這被稱爲過度索引。
3.8優化SQL語句
- 對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
- 應儘量避免在 where 子句中對字段進行 null 值判斷、使用!=或<>操作符、使用or 來連接條件(可以改爲UNION),否則將導致引擎放棄使用索引而進行全表掃描
- 慢查詢優化:
- 首先分析語句,看看是否load了額外的數據,可能是查詢了多餘的行並且拋棄掉了,可能是加載了許多結果中並不需要的列,對語句進行分析以及重寫。
- 分析語句的執行計劃,然後獲得其使用索引的情況,之後修改語句或者修改索引,使得語句可以儘可能的命中索引。
- 如果對語句的優化已經無法進行,可以考慮表中的數據量是否太大,如果是的話可以進行橫向或者縱向的分表。
- MySQL只對一下操作符才使用索引:<, <=, =, >, >=, between, in;以及某些時候的like(不以通配符%或_開頭的情形)。
- Explain sql來分析sql語句:
- table:顯示這一行的數據是關於哪張表的
- type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型爲const、eq_reg、ref、range、index和ALL
- const,system:當MySQL對某查詢某部分進行優化,並轉爲一個常量時,使用這些訪問類型。如果將主鍵置於where列表中,MySQL就能將該查詢轉化爲一個常量。
- eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配,常用於主鍵或者唯一索引掃描;
- ref:非唯一性索引掃描,返回匹配某個單獨值的所有行,常見於使用非唯一索引即唯一索引的非唯一前綴進行查找;
- range:索引範圍掃描,對索引的掃描開始於某一點,返回匹配值的行,常見與between ,< ,>等查詢;
- index : index scan; index 和 all的區別在於index類型只遍歷索引;
- all: full table scan ;MySQL將遍歷全表以找到匹配的行;
- key: 實際使用的索引。如果爲NULL,則沒有使用索引。很少的情況下,MySQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MySQL忽略索引
- key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好
- ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
- rows:MySQL認爲必須檢查的用來返回請求數據的行數
- Extra:關於MySQL如何解析查詢的額外信息。常見的有:
- Using index 使用覆蓋索引。
- Using where 使用了用where子句來過濾結果集。
- Using filesort 使用文件排序,使用非索引列進行排序時出現,非常消耗性能,儘量優化。
- Using temporary 使用了臨時表。
------本篇完------