索引的定義
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構.可以得出索引的本質就是數據結構
你可以簡單理解為"排序好的快速查找數據結構"
在數據之外,數據庫還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構的基礎上實現高級查找算法,這種數據結構就是索引
一般來說索引本身很大,不適合全部存儲在內存中,因此索引往往以索引文件的形式存儲在磁盤上
我們平常所說的索引,如果沒有特別指明,都是指B樹(多路搜索樹,並不一定是二叉的)結構組織的索引,其中聚集索引,次要索引,覆蓋索引
復合索引,前綴索引,唯一索引默認都是使用B+樹索引,統稱索引.當然,除了B+樹這種類型的索引之外,還有哈稀索引(hash index)等
優勢
類似大學圖書館建書目錄索引,提高數據檢索的效率,降低數據庫的IO成本
通過索引列對數據進行排序,降低數據排序成本,降低了CPU的消耗
可以加速表和表之間的連接
劣勢
實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,所以索引也是要占內存空間的
雖然索引大大提高了查詢速度,同時都會降低更新表的速度,如對表進行insert,update和delete
因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件每次更新添加了索引的字段,都會調整因為更新所帶來的鍵值變化后的索引信息
索引只是高效的一個因素,如果你的MySQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢方法
索引的分類
單值索引:即一個索引只包含單個列,一個表不\可以有多個單列索引
唯一索引:索引列的值必須唯一,但允許有控制,例如手機號,銀行卡號等值必須是唯一
復合索引:即一個索引包含多個列,例如手機號和銀行卡號一起,如果一個表中的數據在查詢時有多個字段總是同時出現則這些字段就可以作為復合索引
基本語法
創建:create [unique] index indexName on tbname(columnname(lenght))
更改:alter table tbname add [unique] index [indexName] on (columnname(lenght))
更改:alter table tbname add [unique] fulltext [indexName] on (columnname(lenght))#指定索引為fulltext,用於全文索引
刪除:drop index [indexName] on tbname;
查看:show index from tbname\G;
索引結構
BTree索引
Hash索引
full-text全文索引
R-Tree索引
哪種情況需要創建索引
1.主鍵自動建立唯一索引
2.頻繁作為查詢條件的字段應該創建索引
3.查詢中與其他表關聯的字段,外鍵關系建立索引
4.頻繁更新的字段不適合創建索引,因為每次更新不單單是更新數據還會更新索引
5.Where條件里用得到的字段適合創建索引
6.單鍵/組合索引的選擇問題,在高並發下傾向創建組合索引
7.查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
8.查詢中統計或者分組字段
哪種情況不需要建索引
1.表記錄太少(一般生產環境下,三百萬條記錄性能就可能開始下降,官方說的是五百萬到八百萬)
2.經常增刪改的表
3.某個數據列的值包含許多重復的內容
性能分析
1.MySQL Query Optimizer(查詢優化器)
1.1MySQL中有專門負責優化select語句的優化器模塊,主要功能:通過計算分析系統中收集到的統計信息,為客戶端請求的query提供它認為最有的執行計划(它認為最優的數據檢索方式,但不見得是DBA認為是最優的,這部分是最耗時間的)
1.2當客戶端向MySQL請求一條query,命令解析其模塊完成請求分類,區別是select並轉發給MySQL Query Optimizer時,MySQL Query Optimizer首先會對整條Query進行優化,處理掉一些常量表達式的預算,直接轉換成常量值,並對query中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件,結構調整等,然后分析query中的Hint信息(如果有),看顯示Hint信息是否可以完全確定該query的執行計划,如果沒有Hint或Hint信息不足以完全確定執行計划,則會讀取所涉及對象的統計信息,根據query進行寫相應的計算分析,然后再得出最后的執行計划。
2.MySQL常見瓶頸
CPU:CPU在飽和的時候一般發生在數據裝入內存或從磁盤讀取數據時候
IO:磁盤IO瓶頸發生在裝入數據遠大於內存容量的時候
服務器硬件的性能瓶頸,top,free,iostat和vmstat來查看系統的性能狀態
3.Explain
3.1explain+SQL語句順序解釋
表的讀取順序(數字大的先讀,相同的則由上而下讀取)
數據讀取操作的操作類型
哪些索引可以使用
哪些索引被實際使用
索引總長度
表之間的引用
每張表有多少行被優化器查詢
額外的信息(出現using index較好,出現using filesort較差)
3.2怎么用
explain+SQL語句
執行計划包含以下的信息
id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
導致索引失效的案例
1.建什么索引用什么索引,順序也最好保持一致
2.最佳左前綴索引名稱命名(如字段name,age,city,則索引命名應該是nameAgeCity或者xxx_nameAgeCity,順序很重要)
3.不在索引列上做任何操作(計算,函數,or,類型轉換),會導致索引失效而轉向全表掃描
4.存儲引擎不能使用索引中范圍條件右邊的列(如name='lin' and age>25 and city='qingdao',則age后面的索引會實效)
5.盡量使用覆蓋索引(只訪問索引的查詢(索引列和要查詢的列一致)),減少select *
6.MySQL在使用不等於(!=或者<>)的時候無法使用索引會導致全表掃描
7.is null,is not null 也無法使用索引
8.like以通配符在這('%abc','%abc%')兩種情況會索引實效變成全表掃描,'abc%'則不會,若要'%abc','%abc%'不失效,建議使用覆蓋索引,且查詢的字段要少於索引或者與索引一致,不使用select *。如為name,age,city建了索引,請這么使用:select name或者select age,或者select city或者select name,age,city。如果select name,age,city,email則會全表掃描
9.字符串不加引號索引失效,
10.少用or,用他來連接時索引會失效
11.select * from A where exists (select 1 from where b.id=A.id)#當A表的數據系小於B表時,用exists優於in
12.使用join代替子查詢
數據類型選擇
1.數字類型
Float和double選擇(盡量選擇float)
區分開TINYINT / INT / BIGINT,能確定不會使用負數的字段,建議添加 unsigned定義
能夠用數字類型的字段盡量選擇數字類型而不用字符串類型的
2.字符類型
char,varchar,TEXT的選擇:非萬不得已不要使用 TEXT 數據類型,定長字段,建議使用 CHAR 類型(填空格),不定長字段盡量使用 VARCHAR(自動適應長度,超過階段),且僅僅設定適當的最大長度
3.時間類型
按選擇優先級排序DATE(精確到天)、TIMESTAMP、DATETIME(精確到時間)
4.ENUM
對於狀態字段,可以嘗試使用 ENUM 來存放
5.避免使用NULL字段
很難查詢優化且占用額外索引空間
字符編碼
同樣的內容使用不同字符集表示所占用的空間大小會有較大的差異,所以通過使用合適的字符集,可以幫助我們盡可能減少數據量,進而減少IO操作次數。
1.純拉丁字符能表示的內容,選擇 latin1 字符編碼
2.中文可選用utf-8
3.MySQL的數據類型可以精確到字段,所以當我們需要大型數據庫中存放多字節數據的時候,可以通過對不同表不同字段使用不同的數據類型來較大程度減小數據存儲量,進而降低 IO 操作次數並提高緩存命中率
order by優化
重點:使用order by就需要看會不會產生filesort
mysql支持兩種方式排序,index和filesort,index效率高
盡量使用Index方式排序,避免使用FileSort方式排序
盡可能在索引列上完成排序操作,遵照索引列的最佳左前綴
如果不在索引列上,filesort有兩種算法:雙路排序和單路排序
雙路排序:取一堆數據,要對磁盤進行兩次掃描(mysql4.1之前,后來的版本增加了單路排序)
單路排序:從磁盤讀取查詢需要的所有列,按照order by列在buffer對他們進行排序,然后掃描排序后的列表進行輸出,效率快,但會使用更多的內存空間,因此注意調整sort_buffer_size和max_lenght_for_sort_data參數值(增大值),避免創建tmp文件從而進行多次I/O
group by優化
和order by差不多
先排序后分組,遵照索引列的最佳左前綴
當無法使用索引列時,增大max_lenght_for_sort_data和sort_buffer_size的值
where高於having,能在where限定的條件就不要去having限定了
優化總結
1.開啟慢查詢日志
2.expain+慢SQL分析
3.show profile查詢sql在mysql服務器里面的執行細節和生命周期情況
4.sql數據庫服務器的參數調優