MySql優化

目錄

一、Sql本身優化

1、避免使用 select * ,或當只要一行數據時使用 LIMIT 1

2、避免嵌套子查詢

3、避免使用不等於符號

4、union效率優於or、in

5、Null/Not Null的影響

6、注意範圍查詢邊界值

二、索引優化和最左匹配原則

1、儘量使用全值匹配

2、like查詢

3、不操作索引列

4、多使用覆蓋索引

5、字符串不加引號索引失效

6、範圍條件放最後

三、反範式設計優化

四、物理設計優化

1、字段類型

2、長度設計

3、存儲引擎選擇

五、Mysql服務器優化

六、服務器硬件


一、Sql本身優化

1、避免使用 select * ,或當只要一行數據時使用 LIMIT 1

從數據庫裏讀出越多的數據,那麼查詢就會變得越慢。並且,如果你的數據庫服務器和WEB服務器是兩臺獨立的服務器的話,這還會增加網絡傳輸的負載。

當查詢表的時候,已經知道結果只會有一條結果或只要需要有返回數據時,加上 LIMIT 1 可以增加性能。這樣一樣,MySQL數據庫引擎會在找到一條數據後停止搜索,而不是繼續往後查少下一條符合記錄的數據。

2、避免嵌套子查詢

原SQL查詢關聯表中name字段:

select (select name from testone_copy t2 where t1.id = t2.tId ) from testone t1 

初始這樣的寫法沒什麼問題,但一旦遇到海量數據的時候,查詢效率異常低下。改爲關聯查詢如下:

select name from testone t1 inner join testone_copy t2 on t1.id = t2.tId

可自行測試,效率明顯提升,關聯查詢除了 inner join 還有常用的 left join ,這裏不用 left join 是因爲

  • left join在任何場景下都不會比inner join的執行效率高 因爲left join除了需要所有inner join的結果集以外還需要左表的所有沒有關聯上的數據
  • left join除了要求關聯字段有索引以外,最好將小表作爲左表,因爲檢索的循環次數更少,前提是你的業務邏輯沒問題,因爲不同的寫法邏輯是不一樣的
  • inner join會自動選擇合適的表作爲基礎表,也仍然要求有關聯字段索引,並且最好是int型檢索效率更高
  • left join(左聯接) 返回包括左表中的所有記錄和右表中聯結字段相等的記錄 
    inner join(等值連接) 只返回兩個表中聯結字段相等的行

3、避免使用不等於符號

常見的不等於有 not in、<>、!= 等,有些推薦 <>代替 != 是因爲在某些版本中(如sql2000) != 會造成語法錯誤,但三者的使用都會造成無法使用索引。

4、union效率優於or、in

網上很多的聲音都是說union all 快於 or、in,因爲or、in會導致全表掃描。但實際情況要結合自己的語句,對應的查找字段有建立索引條件,查詢關聯條件要匹配實際業務條件,效率才高。

文章也借鑑 :mysql 實戰 or、in與union all 的查詢效率

以下舉個特別例子,建立簡單的testone表,表中有50W數據,並建立有 val 和 bb 的組合索引和分開的單列索引

實際結果是,使用 or 沒用到索引條件,union all 有用到索引條件,但union all 在聯合查詢時,進行了全表掃描,使得時間長於 or 的使用,所以實際應用要結合SQL和表數據本身來調整。

5、Null/Not Null的影響

  • 很多表都包含可爲NULL的列,即使應用程序並不需要保存NULL也是如此,這是因爲可爲NULL是列的默認屬性(TIMESTAMP除外),然而通常情況下最好指定列爲NOT NULL,除非真的需要存儲NULL值。
  • 如果查詢中包含可爲NULL的列,對MySQL來說更難優化,因爲可爲NULL的列使得索引統計和值比較更加複雜。可爲NULL的列會使用更多的存儲空間,在MySQL裏也需要特殊的處理。當可爲NULL的字段被索引時,每個索引記錄需要一個額外的字節,在MyASIM裏甚至還可能導致固定大小的索引(例如只有一個整數列的索引)變成可變大小的索引。
  • 通常把可爲NULL的列改爲NOT NULL 帶來的性能提升比較小,所以(調憂時)沒有必要首先在現有schema中查找並修改這種情況,除非確定這會導致問題。但是,如果計劃在列上建索引,就應該儘量避免設計爲NULL的列。當然也有一些例外,例如值得一提的是,InnoDB使用單獨的位(Bit)存儲NULL值,所以對於稀疏數據(很多值爲NULL,只有少數行是非NULL)有很好的空間效率。但這一點不適用於MyISAM。

                                                                                            ---引用自《高性能MySQL-第三版》第四章 Schema與數據類型優化

在實際運用中,如果查詢的字段設置爲“允許空值”,is null是可以被索引使用,只是查詢效率會降低很多,這一點可以在mysql官網查看8.2.1.13 IS NULL優化

6、注意範圍查詢邊界值

無論是 >=、<= 或是 between and 的範圍查詢,都要注意邊界值,以上述的50W數據表爲例

在50W數據中,查詢範圍在 【100,56560】的閉區間內,均使用到索引條件,下面把範圍增加1查看下

可以看到查詢改爲全表掃描,沒有使用到索引條件。

在使用範圍查詢時,系統查詢優化時會有個範圍值,超過後使用全表掃描。

二、索引優化和最左匹配原則

索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。即:索引是數據結構

索引分類:

  • 聚集索引:並不是一種單獨的索引類型,而是一種數據存儲方式,具體細節取決於不同的實現。innoDB的聚集索引是在同一個結構中保存B-Tree索引(從技術上來說是B+Tree索引)和數據行。每個表只能有一個聚集索引,因爲目錄只能按照一種方法進行排序 。
  • 非聚集索引:不是聚集索引,就是非聚集索引

索引種類:

  • 普通索引:即一個索引只包含單個列,一個表可以有多個單列索引,僅加速查詢
  • 唯一索引:索引列的值必須是唯一,但允許有空值,(主鍵索引是一種特殊的唯一索引不允許空值)
  • 聯合索引:即一個索引包含多個列
  • 全文索引:FULLTEXT即爲全文索引,目前只有MyISAM引擎支持。(這裏使用的是InnoDB,需要的可以自行搜索)。

    索引文件位置:show global variables like "%datadir%";(datadir是數據庫的數據庫)
    查看索引       :show index from table_name
    創建索引       :create (unique) index index_name on table_name(columnname)
                             alter table 表名 add (unique) index index_name (columnname)
    刪除索引       :drop index index_name on table_name

建立索引也要考慮列的離散型:離散型越高,選擇性越好。計算方式:count(distinct col ) : count (col)

如使用 select count(aa), count(bb) from 表名,誰的值大,說明這一些列的離散度更高!離散度大的列放到聯合索引的前面。

最左匹配原則:對索引關鍵字進行計算(對比),一定是從左向右依次進行,且不可跳過。

口訣:

全值匹配我最愛,最左前綴要遵守;

帶頭大哥不能死,中間兄弟不能斷;

索引列上無計算,範圍之後全失效;

like百分加右邊,覆蓋索引不寫星*;

不等空值還有or,索引失效要少用;

字符串裏有引號,SQL高級也不難。

1、儘量使用全值匹配

2、like查詢

搜索索引關鍵字時,是從左往右依次進行的,只要左邊數值確定,可依次進行

Where 條件中 like abc% :可以使用到索引,注意的是,如果查詢範圍太廣,依舊會然索引失效

like %abc 和 like %abc% 兩者無法使用索引。但可以使用覆蓋索引(下面有介紹)來使索引生效

3、不操作索引列

不在索引列上做任何操作(計算、函數、自動or手動類型轉換),會導致索引失效而轉向全表掃描。即使滿足最左前綴原則,但where條件中使用了函數後,索引失效

4、多使用覆蓋索引

覆蓋索引:如果索引包含所有滿足查詢需要的數據的索引成爲覆蓋索引(Covering Index),也就是平時所說的不需要回表操作。(只訪問索引的查詢(索引列和查詢列一致)),減少select *

判斷標準
使用explain,可以通過輸出的extra列來判斷,對於一個索引覆蓋查詢,顯示爲using index,MySQL查詢優化器在執行查詢前會決定是否有索引覆蓋查詢

具體詳情可參見:mysql高效索引之覆蓋索引

5、字符串不加引號索引失效

如:將某個保存數字的字段更改爲 char類型保存,並對該字段建立索引,在where條件搜索時,不添加引號可以依舊可以查找出數據,但索引無效。

6、範圍條件放最後

存儲引擎不能使用索引中範圍條件後邊的列。

舉例說明:以上述表創建一個 val 和 bb 的聯合索引。

“bb”位於索引最後,使用範圍,通過key_len計算(計算方式這裏展示不介紹)可以看出充分使用到了索引

接下來把條件調換下:

可以看到,雖然有用到索引,但不能充分利用。

對於索引的使用效率,可瞭解下explain執行計劃的使用:MySQL 性能優化神器 Explain 使用分析

最左原則失效?

Mysql使用版本是5.7,在where查詢語句後面,查詢字段不是按索引創建字段的順序查詢,可依然有效。不是最左原則失效,是系統查詢時做了優化,自行排列成最優查詢。

順序爲:val,bb.code 

查詢條件沒按最左原則處理,但系統自動優化排序後,符合“帶頭大哥不能死,中間兄弟不能斷”,因此依舊充分使用到索引。

key_len 的計算(.utf_8 需 +3個長度,允許 null 值  +1個長度),參考:mysql 各數據類型的 大小及長度

以上述爲例,先貼出來下表結構: 

CREATE TABLE `testone` (
  `id` int(11) NOT NULL DEFAULT '0',
  `val` int(11) DEFAULT NULL,
  `bb` int(11) DEFAULT '2',
  `code` varchar(50) DEFAULT 'test',
  PRIMARY KEY (`id`),
  KEY `valindex` (`val`,`bb`,`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 valindex 的索引利用率 key_len = (4+1)+ (4+1)+(50*3+2+1)= 163

要驗證是否可以充分利用索引,提高效率,可參見:Mysql中explain作用詳解

三、反範式設計優化

先了解下原三大範式:

第一範式:所有字段都只有單一屬性,單一屬性的列是由基本數據類型構成,設計出來的表都是簡單的二維表
第二範式:要求表中只具有一個主鍵,不能存在非主鍵列只對部分主鍵的依賴關係。(解決方案:建立中間表)
第三範式:指每一個非主屬性既不部分依賴也不傳遞依於業務主鍵,減少冗餘。(解決方案:建立外鍵表)

反範式設計優化:允許少量冗餘,使用空間獲取時間

四、物理設計優化

1、字段類型

  • 優先考慮數字類型(查詢快)
  • 其次是日期、時間類型(類似數字類型)
  • 最好是字符類型
  • 對於相同級別的數據類型,應優先選擇佔用空間小的數據類型

2、長度設計

  • 定長類型: 存儲空間固定。int,float,double,char,date,time,datetime,year,timestamp.
  • 變長類型:存儲空間可變。varchar,decimal,text.

          varchar 65535 佔用字段總空間
          text 65535 獨立存儲,不佔用字段總空間

3、存儲引擎選擇

  • Mysql默認存儲引擎innodb只顯示支持B-Tree,從技術上來說是B+Tree索引
  • MyISAM

五、Mysql服務器優化

  • window系統轉入linux
  • 優化系統內核

六、服務器硬件

  •     內存不足,添加內存
  •     硬盤空間不足,增加硬盤空間

 

文章參考:

【MySQL】探究之null與not null

MySQL千萬級別優化·中

MySQL索引B+Tree和優化概念-- 03

mysql高級----索引優化(二):索引失效案例(應該避免)

mysql總結之explain

mysql 各數據類型的 大小及長度

mysql explain用法和結果的含義

Mysql中explain作用詳解

PS:如有遺漏或是錯誤,可留言提醒下,方便大家一起學習。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章