MySQL性能調優

計算機內存存取、磁盤存取原理 https://blog.csdn.net/qq_35642036/article/details/82809932

索引

索引概念
索引是一個排序的列表,在這個列表中存儲着索引的值和包含這個值的數據所在行的物理地址,在數據十分龐大的時候,索引可以大大加快查詢的速度,這是因爲使用索引後可以不用掃描全表來定位某行的數據,而是先通過索引表找到該行數據對應的物理地址然後訪問相應的數據。

索引的優缺點
優勢:可以快速檢索,減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序;

劣勢:索引本身也是表,因此會佔用存儲空間,一般來說,索引表佔用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨着數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因爲在修改數據表的同時還需要修改索引表;

索引目前使用主要兩類索引:
hash類型的索引:查詢單條快,範圍查詢慢
btree類型的索引:b+樹,層數越多,數據量指數級增長(我們就用它,因爲innodb默認支持它)

索引的分類
1)常見的索引類型有:主鍵索引、唯一索引、普通索引、全文索引、組合索引

1、主鍵索引:即主索引,根據主鍵pk_clolum(length)建立索引,不允許重複,不允許空值;

ALTER TABLE ‘table_name’ ADD PRIMARY KEY(‘col’);
2、唯一索引:用來建立索引的列的值必須是唯一的,允許空值

create unique index goods_no_unique on t_goods_info (goods_no);

ALTER TABLE ‘table_name’ ADD UNIQUE(‘col’);
3、普通索引:用表中的普通列構建的索引,沒有任何限制

ALTER TABLE ‘table_name’ ADD INDEX index_name(‘col’);
4、全文索引:用大文本對象的列構建的索引(下一部分會講解)

ALTER TABLE ‘table_name’ ADD FULLTEXT(‘col’);
5、組合索引:用多個列組合構建的索引,這多個列中的值不允許有空值

ALTER TABLE ‘table_name’ ADD INDEX index_name(‘col1’,‘col2’,‘col3’);
*遵循“最左前綴”原則,把最常用作爲檢索或排序的列放在最左,依次遞減,組合索引相當於建立了col1,col1col2,col1col2col3三個索引,而col2或者col3是不能使用索引的。

*在使用組合索引的時候可能因爲列名長度過長而導致索引的key太大,導致效率降低,在允許的情況下,可以只取col1和col2的前幾個字符作爲索引

ALTER TABLE ‘table_name’ ADD INDEX index_name(col1(4),col2(3));
表示使用col1的前4個字符和col2的前3個字符作爲索引

2)在索引的分類中,我們可以按照索引的鍵是否爲主鍵來分爲“主索引”和“輔助索引”,使用主鍵鍵值建立的索引稱爲“主索引”,其它的稱爲“輔助索引”。因此主索引只能有一個,輔助索引可以有很多個。

二、索引數據結構

幾種索引數據結構

二叉查找樹     缺點:可能造成線性結構,樹的高度過高,查找效率低下


紅黑樹      特點:能夠自動維持平衡,不至於樹的高度過高。但是如果對於大數據的情況下,因爲數只有兩個節點,故大數據下樹的高度還是會很高。


HASH      特點:精確查詢速度比較快,索引的檢索可以一次定位,不像B-Tree索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次的IO訪問。但是對於範圍查詢,效率就會很低

B-Tree    

HASH 與B-Tree 的區別

1、Hash索引僅僅能夠滿足“=”,“IN”和“<=>”查詢,不能使用範圍查詢。

  由於Hash索引比較的是進行Hash運算之後的Hash值,所以它只能用於等值的過濾,不能用於基於範圍的過濾,因爲進過相應的Hash算法處理之後的Hash值的大小關係,並不能保證和Hash運算前完全一樣。

  2、Hash索引無法被用來避免數據的排序操作

   由於Hash索引中存放的是經過Hash計算之後的Hash值,而且Hash值的大小管理並不一定和Hash運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算。

  3、Hash索引不能利用部分索引查詢

  對於組合索引,Hash索引在計算Hash值的時候是組合索引鍵合併後再一起計算Hashs值,而不是單獨計算Hash值,所以通過組合索引的前面一個或者幾個索引鍵進行查詢的時候,Hash索引也無法被利用。

  4、Hash索引在任何時候都不能避免表掃描

  前面已經知道,Hash索引是將索引鍵通過Hash運算之後,將Hash運算結果的Hash值和對應的行指針信息存放於一個Hash表中,由於不同索引鍵存在相同Hash值,所以即使取滿足某個Hash鍵值的數據的記錄條數,也無法從Hash索引中年直接完成查詢,還要通過訪問表中實際數據進行相應的比較,並得到相應的結果。

  5、Hash索引遇到大量Hash值相等的情況後性能不一定會比B-Tree索引高

  對於選擇性比較低的索引鍵,如果創建Hash索引,那麼將會存在大量記錄指針信息存於同一個Hash值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表數據的訪問,而造成整體性能低下。

@see 索引原理-btree索引與hash索引的區別 https://www.cnblogs.com/zhouguowei/p/9753828.html

索引數據結構

b-樹索引數據結構:主要應用於文件系統和部分數據庫索引,如非關係型數據庫mogodb
下面來具體介紹一下B-樹(Balance Tree),一個m階的B樹具有如下幾個特徵:

1.根結點至少有兩個子女。

2.每個中間節點都包含k-1個元素和k個孩子,其中 m/2 <= k <= m

3.每一個葉子節點都包含k-1個元素,其中 m/2 <= k <= m

4.所有的葉子結點都位於同一層。

5.每個節點中的元素從小到大排列,節點當中k-1個元素正好是k個孩子包含的元素的值域分劃。

b-樹的優點

1.自動維持平衡

B+樹的特徵:

1.有k個子樹的中間節點包含有k個元素(B樹中是k-1個元素),每個元素不保存數據,只用來索引,所有數據都保存在葉子節點。

2.所有的葉子結點中包含了全部元素的信息,及指向含這些元素記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接。

3.所有的中間節點元素都同時存在於子節點,在子節點元素中是最大(或最小)元素。

B+樹的優勢:

1.單一節點存儲更多的元素,使得查詢的IO次數更少。

2.所有查詢都要查找到葉子節點,查詢性能穩定。

3.所有葉子節點形成有序鏈表,便於範圍查詢。

b+樹和b-樹的區別:

1.範圍查詢

索引的使用策略
什麼時候要使用索引?

主鍵自動建立唯一索引;
經常作爲查詢條件在WHERE或者ORDER BY 語句中出現的列要建立索引;
作爲排序的列要建立索引;
查詢中與其他表關聯的字段,外鍵關係建立索引
高併發條件下傾向組合索引;

什麼時候不要使用索引?

經常增刪改的列不要建立索引;
有大量重複的列不建立索引;
表記錄太少不要建立索引;

使用索引的注意事項

1.LIKE操作中,'%aaa%'不會使用索引,也就是索引會失效,但是‘aaa%’可以使用索引;同時在查詢條件中使用正則表達式時,只有在搜索模板的第一個字符不是通配符的情況下才能使用索引。
2.在索引的列上使用表達式或者函數會使索引失效,例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成:select * from users where adddate<’2007-01-01′。
3.在查詢條件中使用<>會導致索引失效。
4.在查詢條件中使用IS NULL會導致索引失效。
5.如果限制條件中其他字段沒有索引,儘量少用or。or兩邊的字段中,如果有一個不是索引字段,而其他條件也不是索引字段,會造成該查詢不走索引的情況。很多時候使用 union all 或者是union(必要的時候)的方式來代替“or”會得到更好的效果
6.儘量不要包括多列排序,如果一定要,最好爲這隊列構建組合索引;
7.索引字段不能太長,如果索引的值很長,那麼查詢的速度會受到影響。例如,對一個CHAR(100)類型的字段進行全文檢索需要的時間肯定要比對CHAR(10)類型的字段需要的時間要多。
長度爲 20 的索引,區分度會高達 90%以上可以使用count(distinct left(列名, 索引長度))/count(*)區分度來確定
8.注意範圍查詢,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a =1 and b=2 c=> 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。

9.關聯查詢時,儘量使用小表驅動大表

sql調優

1.SQL語句中IN包含的值不應過多
MySQL對於IN做了相應的優化,即將IN中的常量全部存儲在一個數組裏面,而且這個數組是排好序的。但是如果數值較多,產生的消耗也是比較大的。再例如:select id from t where num in(1,2,3) 對於連續的數值,能用 between 就不要用 in 了;再或者使用連接來替換

摘自阿里巴巴開發手冊:in 操作能避免則避免,若實在避免不了,需要仔細評估 in 後邊的集合元素數量,控制在 1000 個之內。

2.SELECT語句務必指明字段名稱
SELECT *增加很多不必要的消耗(cpu、io、內存、網絡帶寬),主要是解析得消耗;所以要求直接在select後面接上字段名。


3.儘量用union all代替union
union和union all的差異主要是前者需要將結果集合並後再進行唯一性過濾操作,這就會涉及到排序,增加大量的CPU運算,加大資源消耗及延遲。當然,union all的前提條件是兩個結果集沒有重複數據。

4.使用合理的分頁方式以提高分頁的效率
select id,name from product limit 866613, 20
使用上述sql語句做分頁的時候,可能有人會發現,隨着表數據量的增加,直接使用limit分頁查詢會越來越慢。
優化的方法如下:可以取前一頁的最大行數的id,然後根據這個最大的id來限制下一頁的起點。比如此列中,上一頁最大的id是866612。sql可以採用如下的寫法:
select id,name from product where id> 866612 limit 20


mysql分頁原理:MySQL 並不是跳過 offset 行,而是取 offset+N 行,然後返回放棄前 offset 行,返回 N行,那當 offset 特別大的時候,效率就非常的低下,要麼控制返回的總頁數,要麼對超過特定閾值的頁數進行 SQL 改寫。

5.避免隱式類型轉換
where 子句中出現 column 字段的類型和傳入的參數類型不一致的時候發生的類型轉換,建議先確定where中的參數類型

SQL關鍵字的執行順序

1)Mysql語法順序,即當sql中存在下面的關鍵字時,它們要保持這樣的順序:

select[distinct]
from
join(如left join)
on
where
group by
having
union
order by
limit

2)Mysql執行順序,即在執行時sql按照下面的順序進行執行:

from  
on  
join  
where  
group by  
having  
select  
distinct  
union  
order by  

@see Mysql 語句執行順序 https://blog.csdn.net/jintao_ma/article/details/51253356#

mysql中in 和exists 區別。

exists:
exists對外表用loop逐條查詢,每次查詢都會查看exists的條件語句,當 exists裏的條件語句能夠返回記錄行時(無論記錄行是的多少,只要能返回),條件就爲真,返回當前loop到的這條記錄,反之如果exists裏的條 件語句不能返回記錄行,則當前loop到的這條記錄被丟棄,exists的條件就像一個bool條件,當能返回結果集則爲true,不能返回結果集則爲 false

not exists:
not exists與exists相反,也就是當exists條件有結果集返回時,loop到的記錄將被丟棄,否則將loop到的記錄加入結果集

in
in是把外表和內表做hash連接,先查詢內表,再把內表結果與外表匹配,對外表使用索引(外表效率高,可用大表),而內表多大都需要查詢,不可避免,故外表大的使用in,可加快效率。

@see MySQL中exists和in的區別及使用場景 https://www.cnblogs.com/xiaoxiong-kankan/p/7928153.html

索引的優化

1、最左前綴

索引的最左前綴和和B+Tree中的“最左前綴原理”有關,舉例來說就是如果設置了組合索引《col1,col2,col3》那麼以下3中情況可以使用索引:col1,《col1,col2》,《col1,col2,col3》,其它的列,比如《col2,col3》,《col1,col3》,《col2,col3》等等都是不能使用索引的。
根據最左前綴原則,我們一般把排序分組頻率最高的列放在最左邊,以此類推。

最左前綴原理

mysql創建聯合索引的規則是首先會對聯合合索引的最左邊的,也就是第一個字段col1的數據進行排序,在第一個字段的排序基礎上,然後再對後面第二個字段col2進行排序。其實就相當於實現了類似 order by col1 col2這樣一種排序規則。

組合索引的優點

1.效率高
使用組合索引,只需查找索引一次,而如果多個列分別使用索引,那麼命中第一個索引後,還得再去命中第二個索引,這樣性能就會有所下降。
如:有1000W條數據的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假設假設每個條件可以篩選出10%的數據,如果只有單值索引,那麼通過該索引能篩選出1000W10%=100w條數據,然後再回表從100w條數據中找到符合col2=2 and col3= 3的數據,然後再排序,再分頁;如果是聯合索引,通過索引篩選出1000w10% 10% *10%=1w,效率提升可想而知!

2.減少開銷
建一個聯合索引(col1,col2,col3),實際相當於建了(col1),(col1,col2),(col1,col2,col3)三個索引。每多一個索引,都會增加寫操作的開銷和磁盤空間的開銷。對於大量數據的表,使用聯合索引會大大的減少開銷!

3.覆蓋索引
對聯合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那麼MySQL可以直接通過遍歷索引取得數據,而無需回表,這減少了很多的隨機io操作。減少io操作,特別的隨機io其實是dba主要的優化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升性能的優化手段之一。

2、帶索引的模糊查詢優化

在上面已經提到,使用LIKE進行模糊查詢的時候,’%aaa%'不會使用索引,也就是索引會失效。如果是這種情況,只能使用全文索引來進行優化

主索引和輔助索引

在索引的分類中,我們可以按照索引的鍵是否爲主鍵來分爲“主索引”和“輔助索引”,使用主鍵鍵值建立的索引稱爲“主索引”,其它的稱爲“輔助索引”。因此主索引只能有一個,輔助索引可以有很多個。

聚集索引與非聚集索引

聚集(clustered)索引,也叫聚簇索引。

定義:數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。

數據行的物理順序與列值的順序相同,如果我們查詢id比較靠後的數據,那麼這行數據的地址在磁盤中的物理地址也會比較靠後。而且由於物理排列方式與聚集索引的順序相同,所以也就只能建立一個聚集索引了。

非聚集(unclustered)索引。

定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。

其實按照定義,除了聚集索引以外的索引都是非聚集索引,只是人們想細分一下非聚集索引,分成普通索引,唯一索引,全文索引。如果非要把非聚集索引類比成現實生活中的東西,那麼非聚集索引就像新華字典的偏旁字典,他結構順序與實際存放順序不一定一致。

兩種索引數據查找過程如下:
在這裏插入圖片描述

總結:

1.使用聚集索引的查詢效率要比非聚集索引的效率要高,但是如果需要頻繁去改變聚集索引的值,寫入性能並不高,因爲需要移動對應數據的物理位置。
2.非聚集索引在查詢的時候可以的話就避免二次查詢,這樣性能會大幅提升。

MySQL Explain

explain這個命令可以來查看這些SQL語句的執行計劃,查看該SQL語句有沒有使用上了索引,有沒有做全表掃描,這都可以通過explain命令來查看。

expain出來的信息有10列,分別是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra,下面對這些字段出現的可能進行解釋:

1、 id

SQL執行的順序的標識,SQL從大到小的執行

1)id相同時,執行順序由上至下

2)如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行

3)id如果相同,可以認爲是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行

2、select_type

示查詢中每個select子句的類型

(1) SIMPLE(簡單SELECT,不使用UNION或子查詢等)

(2) PRIMARY(查詢中若包含任何複雜的子部分,最外層的select被標記爲PRIMARY)

(3) UNION(UNION中的第二個或後面的SELECT語句)

(4) DEPENDENT UNION(UNION中的第二個或後面的SELECT語句,取決於外面的查詢)

(5) UNION RESULT(UNION的結果)

(6) SUBQUERY(子查詢中的第一個SELECT)

(7) DEPENDENT SUBQUERY(子查詢中的第一個SELECT,取決於外面的查詢)

(8) DERIVED(派生表的SELECT, FROM子句的子查詢)

(9) UNCACHEABLE SUBQUERY(一個子查詢的結果不能被緩存,必須重新評估外鏈接的第一行)

3、table

顯示這一行的數據是關於哪張表的,有時不是真實的表名字,看到的是derivedx(x是個數字,我的理解是第幾步執行的結果)

mysql> explain select * from (select * from ( select * from t1 where id=2602) a) b;
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  3 | DERIVED     | t1         | const  | PRIMARY,idx_t1_id | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

4、type

表示MySQL在表中找到所需行的方式,又稱“訪問類型”。

常用的類型有: ALL, index, range, ref, eq_ref, const, system, NULL(從左到右,性能從差到好)

ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行

index: Full Index Scan,index與ALL區別爲index類型只遍歷索引樹

range:只檢索給定範圍的行,使用一個索引來選擇行

ref: 表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值

eq_ref: 類似ref,區別就在使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者 unique key作爲關聯條件

const:表示索引一次就能找到結果(索引可以是主鍵或惟一索引)。因爲只有一行,這個值實際就是常數,因爲MYSQL先讀這個值然後把它當做常數來對待

system: 表只有一行:system表。這是const連接類型的特殊情況

NULL: MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列裏選取最小值可以通過單獨索引查找完成。

5、possible_keys

指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢使用

6、Key

key列顯示MySQL實際決定使用的鍵(索引),如果沒有選擇索引,鍵是NULL。
要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
7、key_len

表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度(key_len顯示的值爲索引字段的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的)

不損失精確性的情況下,長度越短越好

8、ref

表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值

9、rows

表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數(可以快速判斷是否有命中索引

10、Extra

該列包含MySQL解決查詢的詳細信息,有以下幾種情況:

Using where:列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同一個索引的部分的時候,表示mysql服務器將在存儲引擎檢索行後再進行過濾

Using temporary:表示MySQL需要使用臨時表來存儲結果集,常見於排序和分組查詢

Using filesort:MySQL中無法利用索引完成的排序操作稱爲“文件排序”

Using join buffer:改值強調了在獲取連接條件時沒有使用索引,並且需要連接緩衝區來存儲中間結果。如果出現了這個值,那應該注意,根據查詢的具體情況可能需要添加索引來改進能。

Impossible where:這個值強調了where語句會導致沒有符合條件的行。

Select tables optimized away:這個值意味着僅通過使用索引,優化器可能僅從聚合函數結果中返回一行

參考資料:
1.漫畫算法:什麼是 B 樹?http://blog.jobbole.com/111757/
2.漫畫:什麼是 B+ 樹??https://www.sohu.com/a/156886901_479559
3.深入理解MySQL索引原理和實現——爲什麼索引可以加速查詢?https://blog.csdn.net/tongdanping/article/details/79878302
4.Mysql聯合索引最左匹配原則 https://segmentfault.com/a/1190000015416513
5.聚集索引與非聚集索引的總結 https://www.cnblogs.com/s-b-b/p/8334593.html

發佈了67 篇原創文章 · 獲贊 22 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章