MySQL資料庫SQL優化(原則)

2021-08-02 07:05:19 字數 4556 閱讀 4271

通過web應用關係圖譜可以看出web應用的響應速度取決於多個方面

優化方法

1、改變 sql 執行計畫

明確了優化目標之後,我們需要確定達到我們目標的方法。對於 sql 語句來說,達到上述2個目標的方法其實只有乙個,那就是改變 sql 的執行計畫,讓他盡量「少走彎路」,盡量通過各種「捷徑」來找到我們需要的資料,以達到 「減少 io 次數」 和 「降低 cpu 計算」 的目標;

2、提公升吞吐速度

考慮伺服器效能壓力,mysql效能壓力;適當考慮犧牲記憶體換取速度;

常見誤區

count(1)和count(primary_key) 優於 count(*)

很多人為了統計記錄條數,就使用 count(1) 和 count(primary_key) 而不是 count(*) ,他們認為這樣效能更好,其實這是乙個誤區。對於有些場景,這樣做可能性能會更差,應為資料庫對 count(*) 計數操作做了一些特別的優化。

count(column) 和 count(*) 是一樣的

這個誤區甚至在很多的資深工程師或者是 dba 中都普遍存在,很多人都會認為這是理所當然的。實際上,count(column) 和 count(*) 是乙個完全不一樣的操作,所代表的意義也完全不一樣。

count(column) 是表示結果集中有多少個column欄位不為空的記錄

count(*) 是表示整個結果集有多少條記錄

select a,b from … 比 select a,b,c from … 可以讓資料庫訪問更少的資料量

這個誤區主要存在於大量的開發人員中,主要原因是對資料庫的儲存原理不是太了解。

實際上,大多數關係型資料庫都是按照行(row)的方式儲存,而資料訪問操作都是以乙個固定大小的io單元(被稱作 block 或者 page)為單位,一般為4kb,8kb… 大多數時候,每個io單元中儲存了多行,每行都是儲存了該行的所有字段(lob等特殊型別字段除外)。

所以,我們是取乙個字段還是多個字段,實際上資料庫在表中需要訪問的資料量其實是一樣的。

當然,也有例外情況,那就是我們的這個查詢在索引中就可以完成,也就是說當只取 a,b兩個欄位的時候,不需要回表,而c這個欄位不在使用的索引中,需要回表取得其資料。在這樣的情況下,二者的io量會有較大差異。

order by 一定需要排序操作

我們知道索引資料實際上是有序的,如果我們的需要的資料和某個索引的順序一致,而且我們的查詢又通過這個索引來執行,那麼資料庫一般會省略排序操作,而直接將資料返回,因為資料庫知道資料已經滿足我們的排序需求了。

實際上,利用索引來優化有排序需求的 sql,是乙個非常重要的優化手段

執行計畫中有 filesort 就會進行磁碟檔案排序

有這個誤區其實並不能怪我們,而是因為 mysql 開發者在用詞方面的問題。filesort 是我們在使用 explain 命令檢視一條 sql 的執行計畫的時候可能會看到在 「extra」 一列顯示的資訊。

實際上,只要一條 sql 語句需要進行排序操作,都會顯示「using filesort」,這並不表示就會有檔案排序操作。

基本原則

子查詢優化

很多查詢中需要使用子查詢。使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的sql操作,同時也可以避免事務或者表鎖死。子查詢可以使查詢語 句很靈活,但子查詢的執行效率不高。子查詢時,mysql需要為內層查詢語句的查詢結果建立乙個臨時表。然後外層查詢語句再臨時表中查詢記錄。查詢完畢 後,mysql需要撤銷這些臨時表。因此,子查詢的速度會受到一定的影響。如果查詢的資料量比較大,這種影響就會隨之增大。

在mysql中可以使用連線查 詢來替代子查詢。連線查詢不需要建立臨時表,其速度比子查詢要快。(使用連線(join)來代替子查詢 )

盡量少 join

mysql 的優勢在於簡單,但這在某些方面其實也是其劣勢。mysql 優化器效率高,但是由於其統計資訊的量有限,優化器工作過程出現偏差的可能性也就更多。對於複雜的多表 join,一方面由於其優化器受限,再者在 join 這方面所下的功夫還不夠,所以效能表現離 oracle 等關係型資料庫前輩還是有一定距離。但如果是簡單的單錶查詢,這一差距就會極小甚至在有些場景下要優於這些資料庫前輩。

盡量少排序

排序操作會消耗較多的 cpu 資源,所以減少排序可以在快取命中率高等 io 能力足夠的場景下會較大影響 sql 的響應時間。

對於mysql來說,減少排序有多種辦法,比如:

上面誤區中提到的通過利用索引來排序的方式進行優化

減少參與排序的記錄條數

非必要不對資料進行排序 …

盡量避免 select *

很多人看到這一點後覺得比較難理解,上面不是在誤區中剛剛說 select 子句中字段的多少並不會影響到讀取的資料嗎?

是的,大多數時候並不會影響到 io 量,但是當我們還存在 order by 操作的時候,select 子句中的字段多少會在很大程度上影響到我們的排序效率,這一點可以通過我之前一篇介紹 mysql order by 的實現分析 的文章中有較為詳細的介紹。

此外,上面誤區中不是也說了,只是大多數時候是不會影響到 io 量,當我們的查詢結果僅僅只需要在索引中就能找到的時候,還是會極大減少 io 量的。

盡量用 join 代替子查詢

雖然 join 效能並不佳,但是和 mysql 的子查詢比起來還是有非常大的效能優勢。mysql 的子查詢執行計畫一直存在較大的問題,雖然這個問題已經存在多年,但是到目前已經發布的所有穩定版本中都普遍存在,一直沒有太大改善。雖然官方也在很早就承認這一問題,並且承諾盡快解決,但是至少到目前為止我們還沒有看到哪乙個版本較好的解決了這一問題。

盡量少 or

當 where 子句中存在多個條件以「或」並存的時候,mysql 的優化器並沒有很好的解決其執行計畫優化問題,再加上 mysql 特有的 sql 與 storage 分層架構方式,造成了其效能比較低下,很多時候使用 union all 或者是union(必要的時候)的方式來代替「or」會得到更好的效果。

盡量用 union all 代替 union

union 和 union all 的差異主要是前者需要將兩個(或者多個)結果集合並後再進行唯一性過濾操作,這就會涉及到排序,增加大量的 cpu 運算,加大資源消耗及延遲。所以當我們可以確認不可能出現重複結果集或者不在乎重複結果集的時候,盡量使用 union all 而不是 union。

盡量早過濾

這一優化策略其實最常見於索引的優化設計中(將過濾性更好的字段放得更靠前)。

在 sql 編寫中同樣可以使用這一原則來優化一些 join 的 sql。比如我們在多個表進行分頁資料查詢的時候,我們最好是能夠在乙個表上先過濾好資料分好頁,然後再用分好頁的結果集與另外的表 join,這樣可以盡可能多的減少不必要的 io 操作,大大節省 io 操作所消耗的時間。

避免型別轉換

這裡所說的「型別轉換」是指 where 子句中出現 column 欄位的型別和傳入的引數型別不一致的時候發生的型別轉換:

1、人為在column_name 上通過轉換函式進行轉換

直接導致 mysql(實際上其他資料庫也會有同樣的問題)無法使用索引,如果非要轉換,應該在傳入的引數上進行轉換

2、由資料庫自己進行轉換

如果我們傳入的資料型別和字段型別不一致,同時我們又沒有做任何型別轉換處理,mysql 可能會自己對我們的資料進行型別轉換操作,也可能不進行處理而交由儲存引擎去處理,這樣一來,就會出現索引無法使用的情況而造成執行計畫問題。

子查詢優化

優先優化高併發的 sql,而不是執行頻率低某些「大」sql

對於破壞性來說,高併發的 sql 總是會比低頻率的來得大,因為高併發的 sql 一旦出現問題,甚至不會給我們任何喘息的機會就會將系統壓跨。而對於一些雖然需要消耗大量 io 而且響應很慢的 sql,由於頻率低,即使遇到,最多就是讓整個系統響應慢一點,但至少可能撐一會兒,讓我們有緩衝的機會。

從全域性出發優化,而不是片面調整

sql 優化不能是單獨針對某乙個進行,而應充分考慮系統中所有的 sql,尤其是在通過調整索引優化 sql 的執行計畫的時候,千萬不能顧此失彼,因小失大。

盡可能對每一條執行在資料庫中的sql進行 explain

優化 sql,需要做到心中有數,知道 sql 的執行計畫才能判斷是否有優化餘地,才能判斷是否存在執行計畫問題。在對資料庫中執行的 sql 進行了一段時間的優化之後,很明顯的問題 sql 可能已經很少了,大多都需要去發掘,這時候就需要進行大量的 explain 操作收集執行計畫,並判斷是否需要進行優化。

我的mysql資料庫sql優化原則

原文 我的mysql資料庫sql優化原則 這裡的原則 只是針對mysql資料庫,其他的資料庫 某些是殊途同歸,某些還是存在差異。我總結的也是mysql普遍的規則,對於某些特殊情況得特殊對待。在構造sql語句的時候養成良好的習慣 原來語句 select from admin 優化為 select ad...

MySql 資料庫優化原則

1.定長與變長分離 型別為定長的列,如int char 4 time等,放在乙個表中。型別為變長的列,varchar text blob,放在另乙個表中。兩張表通過主鍵關聯起來。2.常用和不常用分離 常用字段和不常用字段分離。將常用字段,如個人資訊表中的姓名,出生日期,放在一張表中。將不常用字段,如...

mysql資料庫sql優化

sql優化 本文件描述了mysql資料庫的sql優化,從整體上描述mysql資料庫的sql執行過程,及整個流程上相關優化點,重點描述innodb儲存引擎的索引優化及鎖機制,旨在為讀者提供在mysql上做sql優化的思路,達到授人以漁的效果,希望能為讀者帶來收穫。效能 完成某項任務所需要的時間度量,即...