MySQL 優化專題拓展

一、SQL 優化

1、分析和定位策略

  • 通過 show status 瞭解各種 SQL 的執行頻率
  • 定位執行效率低的 SQL 語句:①通過慢日誌定位;②使用 show processlist 命令查看當前在進行的線程
  • 通過 explain 分析低效 SQL
  • 通過 show profile 分析 SQL
  • 通過 trace 分析優化器的選擇

2、優化

1、大批量插入數據,使用如下方式能快速導入大量數據(在 myisam 引擎下速度更爲顯著):

alter table 表名 disable keys;

Loading the data

Alter table 表名 enable keys;

2、優化 insert 語句:

  • ①對同一客戶插入很多行,儘量使用多個值表的 insert 語句,能大大縮減客戶端與數據 庫之間的連接。例如 insert into 表名 values(1,2),(1,3),(1,4)····
  • ②對不同客戶插入很多行,可以使用 insert delayed 語句更高速
  • ③將索引文件和數據文件分在不同的磁盤上存放
  • ④從一個文本文件裝載一個表時,使用 load data infile,速度會比 insert 20 倍左右

3、優化 order by 語句:

  • mysql 中的兩種排序方式:第一種是有序索引順序掃描直接返回有序數據;第二種是 通過對返回數據進行排序(Filesort 排序)
  • Filesort 優化:通過兩次掃描算法和一次掃描算法

4、優化 group by 語句:使用 group by null 可以避免用戶排序結果的消耗

5、優化嵌套查詢:子查詢可以一次性完成多個步驟查詢,同時可以避免事務或者是表死鎖。但是在有些情況下,連接查詢可以代替子查詢

6、優化 or 條件:正確使用 or 條件查詢,當時在對有獨立索引的列查詢時 or 操作能夠快速查找到結果;而在對有複合索引的列上做 or 操作時,卻不能用到索引

7、優化分頁查詢:

①思路一:在索引上完成排序分頁的操作,最後根據主鍵關聯回原表查詢所需要的其他列內容,這種方式讓 mysql 掃描儘可能少的頁面來提高分頁效率

②思路二:把 limit 查詢轉換成某個位置查詢。這樣把 limit m,n 轉換成 limit n 只適合在排序字段不會出現重複值的環境下

8、使用 SQL 提示:

  • use index:在查詢語句中表名的後面,添加 use index 來提供 mysql 去參考的索引列表,讓mysql 不再去考慮其他索引
  • ignore index:使用 ignore index 可以讓 mysql 忽略一個或者多個索引
  • force index:強制 mysql 使用一個特定的索引,一定情況下可以避免全表掃描

PS:索引問題

1、索引的存儲分類

  • B-Tree 索引:最常見的索引,大部分引擎都支持
  • Hash 索引:只有 memory 引擎支持
  • R-Tree 索引(空間索引):使用很少,只做瞭解
  • Full-text(全文索引):主要用於全文索引,innodb mysql5.6 開始提供支持

2Mysql 中使用索引的場景

①匹配全值:對索引中所有列都指定具體值,即對索引中的所有列都有等值匹配的條件

例:select * from rental where rental_date=’2017-06-27 17:40:59’ and customer_id=343;

②匹配值的範圍查詢:對索引的值能夠進行範圍查找

例:select * from rental where customer_id>=373 and customer_id<400;

③匹配最左前綴:僅僅使用索引中的最左邊列進行查找。

例:在 A+B+C 字段上的聯合索引能夠被 AA+BA+B+C 的等值查詢利用,但是不能被 B、B+C 的等值查詢利用到。

④僅僅對索引進行查詢,檔查詢的列都在索引的字段中時,查詢的效率更高

⑤匹配列前綴:僅僅使用索引中的第一列,並且只包含索引第一列的開頭一部分進行查找

⑥索引匹配部分精確而其他部分進行範圍匹配:

例:select a_id from rental where rental_date=’2006-02-14’ and customer_id >=300 and customer_id < 400

⑦如果列名是索引,那麼使用 column_name is null 就會使用索引

3、存在索引但不能使用索引的場景

  • ①以%開頭的 Like 查詢不能夠利用索引
  • ②數據類型出現隱式轉換的時候也不會使用索引,特別是當列類型是字符串,一定要在 where 條件中把字符串常量值用引號引起來,否則即便是有索引也是無效的
  • ③複合索引的情況下,假如查詢條件不滿足最左原則,是不會使用索引的
  • ④如果 mysql 估計使用索引比全表掃描更慢,則不使用索引
  • ⑤用 or 分割開的條件,如果 or 前的條件中的列有索引,而後面的列中沒有索引,那麼涉及的索引都不會被用到

二、優化數據庫對象

1、優化表的數據類型:表需要使用何種數據類型是需要根據應用來判斷的。可以使用函數procedure analyse()對當前應用的表進行分析,可以根據當前表提出優化建議

2、通過拆分提高表的訪問效率:

①垂直拆分:把主碼和一些列放到一個表,然後把主碼和另外的列放到另一個表中

②水平拆分:根據一列或多列的值把數據行放到兩個獨立的表中

3、使用中間表提高統計查詢速度:

①中間表複製源表部分數據,並且與源表相“隔離”,在中間表上做統計查詢不會對在線用戶產生負面影響

②中間表上可以靈活地添加索引或者增加臨時用的新字段,從而達到提高統計查詢效率和輔助統計查詢作用

三、鎖問題

1MySQL 3 種鎖

①表(級)鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突概率最高,併發度最低(MyISAM,鎖住整個表,可同時讀,不可寫)

②行(級)鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度小,發生鎖衝突概率最低,併發度也最高(InnoDB,單獨的一行記錄加鎖)

③頁面鎖:開銷和加鎖時間介於表鎖和行鎖之間;會出現死鎖;鎖定粒度介於表鎖和行鎖之間,併發度一般

  行鎖 表鎖 頁面鎖
MyISAM    
BDB  
InnoDB  

2MyISAM 的表級鎖

①兩種模式:

表共享讀鎖(所有用戶可以同時去讀同一個加了該表鎖的表,但是不能去對其進行其他操作)

表獨佔寫鎖(一個用戶在對加了該表鎖的表進行寫操作的時候,其他用戶不能對其進行操作)。MyISAM 表的讀操作與寫操作之間,以及寫操作之間是串行的,只允許上述其中一種操作進行

②加鎖:MyISAM 在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執

行更新操作(UPDATEDELETEINSERT 等)前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,都是由 MyISAM 引擎自動完成加鎖

MyISAM 鎖調度:MyISAM 存儲引擎的讀鎖和寫鎖是互斥的,讀寫操作是串行的。當一個進程請求某個 MyISAM 表的讀鎖,同時另一個進程也請求同一表的寫鎖,此時 MySQL會讓寫進程先獲得鎖。不僅如此,即使讀請求先到鎖等待隊列,寫請求後到,寫鎖也會插到讀鎖請求之前

3InnoDB 的鎖

①幾種鎖模式:

共享鎖(S 鎖):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。

排它鎖(X 鎖):允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享讀鎖和排他寫鎖。另外,爲了允許行鎖和表鎖共存,實現多粒度鎖機制

意向共享鎖(IS 鎖):事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的 IS 鎖。

意向排它鎖(IX 鎖):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的 IX 鎖。

②加鎖方式:意向鎖是 InnoDB 自動加的,不需用戶干預。對於 UPDATEDELETE INSERT 語句,InnoDB 會自動給涉及數據集加排他鎖(X);對於普通 SELECT 語句,InnoDB 不會加任何鎖。

③在不通過索引條件查詢的時候,InnoDB 確實使用的是表鎖,而不是行鎖。

④由於 MySQL 的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現鎖衝突

⑤當表有多個索引的時候,不同的事務可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB 都會使用行鎖來對數據加鎖。

4、鎖使用總結:

①表鎖更適合與以查詢爲主,只有少量按索引條件更新數據的應用,如 Web 應用;

②行鎖更適合於有大量按索引條件併發更新少量不同數據,同時又有併發查詢的應用,入一些在線事務處理;

四、應用優化

1、使用連接池

連接池:需要訪問數據庫的的地方,都已經預先創建好,可以直接獲取鏈接,分配給應用使用,大大減少了創建新連接所耗費的資源。在訪問結束後,鏈接將重新交還給連接池,以供新訪問使用。

2、減少對 mysql 的訪問

  • 避免對同一數據做重複檢索
  • 使用查詢緩存(query cache
  • 增加 cache

PS:第③個和第②個作用差不多,只是 cache 層比 query cache 要更大,層次要深點,cache 層可以看做是 mysql 的二級數據庫,query cache 相當於 mysql 內部的緩存。

3、負載均衡:是重用的一種優化方式,採用某種均衡算法,將固定的負載量分佈到不同的服務器上,以此來減輕單臺服務器的負載均衡,達到優化的目的。

  • 利用 mysql 複製分流查詢操作:一個主服務器承擔更多操作,而多臺從服務器承擔產查詢操作,主從之間通過複製實現數據的同步。多臺從服務器一方面用來確保可用性,一方面可以創建不同的索引以滿足不同的查詢的需要。
  • 採用分佈式數據庫架構:分佈式的數據庫架構適合大數據量、負載高的情況,它具有良好的擴展性和高可用性。(該情況只支持 innodb 存儲引擎)。

4、其他優化措施

  • ①對於沒有刪除行操作的 myisam 表,插入操作和查詢操作可以並行進行,因爲沒有刪除操作的表查詢期間不會阻塞插入操作。
  • ②充分利用列有默認值的事實,只有當插入的值不同於默認值時,才明確地插入值。這會減mysql 需要做的語法分析從而提升插入速度 。
  • ③表的字段儘量不使用自增長變量,在高併發的情況下該字段的自增長可能對效率有比較大的影響

概念補充

  • ①更新丟失(Lost Update:當兩個或多個事務選擇同一行,然後基於最初選定的值更新該 行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題--最後的更新覆蓋 了由其他事務所做的更新。
  • ②髒讀(Dirty Reads:一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”數據,並據此做進一步的處理,就會產生未提交的數據依賴關係。 這種現象被形象地叫做"髒讀"
  • ③不可重複讀(Non-Repeatable Reads:一個事務在讀取某些數據後的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象就叫做“不可重複讀”。
  • ④幻讀(Phantom Reads:一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發 現其他事務插入了滿足其查詢條件的新數據,這種現象就稱爲“幻讀”。
  • ⑤死鎖(Deadlock:是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種 互相等待的現象,這些永遠在互相等待的進程稱爲死鎖進程。表級鎖不會產生死鎖,所以解決死鎖主要還是真對於最常用的 InnoDBPS:在讀取數據前,對其加鎖,阻止其他事務對數據進行修改可避免髒讀、不可重複讀、幻讀
  • ⑥悲觀鎖(Pessimistic Lock:悲觀鎖的特點是先獲取鎖,再進行業務操作,即“悲觀”的認爲獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作
  • ⑦樂觀鎖(Optimistic Lock:樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即 “樂觀”的認爲拿鎖多半是會成功的,因此在進行完業務操作需要實際更新數據的最後一步再去拿一下鎖就好
  • ⑧熱備份:熱備份是在數據庫運行的情況下,備份數據庫的方法。即熱備份是系統處於正常運轉狀態下的備份
  • ⑨冷備份:冷備份發生在數據庫已經正常關閉的情況下,當正常關閉時會提供一個完整的數據庫。冷備份時將關鍵性文件拷貝到另外的位置的一種說法。冷備份是最快和最安全的方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章