天天看點

盤點一下影響MySQL性能的因素

既然要優化資料庫,我們就首先要知道,優化的是什麼,或者說:什麼因素影響了資料庫的性能。

影響資料庫因素主要因素總結如下:

  1. 商業需求對性能的影響*
  2. 系統架構(存儲架構)及實作對性能的影響*
  3. query語句對資料庫性能的影響*
  4. Schema設計對系統性能影響*
  5. 硬體環境對資料庫的性能的影響*

商業需求對性能的影響

不合理需求造成資源投入産出比過低,這裡我們就用一個看上去很簡單的功能來分析。

需求:一個論壇文章總量的統計

附加要求:實時更新

從功能上來看非常容易實作,執行一條 SELECT COUNT(*) from 表名的 Query 就可以得到結果。

但是,如果我們采用不是 MyISAM 存儲引擎,而是使用的 Innodb 的存儲引擎,那麼大家可以試想一下,如果存放文章的表中已經有上千萬的文章的時候,執行這條 Query 語句需要多少成本?

恐怕再好的硬體裝置,都不可能在 10 秒之内完成一次查詢吧。

注:沒有 where 的 count(* ) 使用 MyISAM 要比 InnoDB 快得多。因為 MyISAM 内置了一個計數器,count(* ) 時它直接從計數器中讀,而 InnoDB 必須掃描全表。是以在 InnoDB 上執行 count(*) 時一般要伴随 where,且 where 中要包含主鍵以外的索引列。

既然這樣查詢不行,那我們是不是該專門為這個功能建一個表,就隻有一個字段,一條記錄,就存放這個統計量,每次有新的文章産生的時候,都将這個值增加 1。

這樣我們每次都隻需要查詢這個表就可以得到結果了,這個效率肯定能夠滿足要求了。

确實,查詢效率肯定能夠滿足要求,可是如果文章産生很快,在高峰時期可能每秒就有幾十甚至上百個文章新增操作的時候,恐怕這個統計表又要成為大家的噩夢了。

要麼因為并發的問題造成統計結果的不準确,要麼因為鎖資源争用嚴重造成整體性能的大幅度下降。

其實這裡問題的焦點不應該是實作這個功能的技術細節,而是在于這個功能的附加要求“實時更新”上面。

當一個論壇的文章數量很大了之後,到底有多少人會關注這個統計資料是否是實時變化的?

有多少人在乎這個資料在短時間内的不精确性?

恐怕不會有人會盯着這個統計數字并追究當自己發了一個文章然後回頭重新整理頁面發現這個統計數字沒有加 1 吧?

是以隻要去掉了這個“實時更新”的附加條件,就可以非常容易的實作這個功能了。

就像之前所提到的那樣,通過建立一個統計表,然後通過一個定時任務每隔一定時間段去更新一次裡面的統計值,這樣既可以解決統計值查詢的效率問題,又可以保證不影響新發貼的效率,一舉兩得。

系統架構及實作對性能的影響

所有資料都是适合在資料庫中存放的嗎?

資料庫為我們提供了太多的功能,反而讓很多并不是太了解資料庫的人,錯誤的使用資料庫中很多并不太擅長、或對性能影響很大的功能,最後卻全部怪罪到資料庫身上。

比如有些資料需要考慮是否存儲在MySQL

  1. 流水隊列資料
  2. 二進制多媒體資料
  3. 超大的文本資料
  4. 其它使用者上傳的檔案、圖檔等資源

是否考慮了緩存

對于 Web 系統或者 APP 應用,是否有大量熱讀資料及無需及時變更的資料,然而這些資料可以考慮緩存起來,提高 MySQL 的性能及節約 DB 資源。比如筆者公司的優惠券清單、廣告清單、配置規則資訊等,屬于使用者附表資訊,無需頻繁更新,可以利用 Redis 緩存,讓應用跑的更快,使用者體驗更好。

query 語句對資料庫性能的影響

開發人員不能隻關注查詢結果不關注查詢過程,比如每個使用者查詢各自相冊清單(假設每個列顯示 10 張相片),能夠在相片後有留言,我們要檢視留言的數量。

實作的話有好幾種方案。

方案1:
select id,subject,url from photo where user_id=? limit 10           

複制

通過第一步的結果循環10次執行

select count(*) from photo_comment where photo_id=?           

複制

方案2:

第一步和上面是一樣的,第二步通過程式拼裝上面的到的 10 個 photo_id,通過 in 查詢,

select photo_id,count(*) from photo_comment where photo_id in(?)group by photo_id"           

複制

一次得到 10 個 photo_id 所有的回複數量。

簡要分析的話,方案2更簡單一些。

也可以根據 explain 執行分析,具體看執行計劃和性能損耗情況(cpu、io 的損耗情況)

mysql>set profiling=1;mysql>select id,subject,url from photo where user_id=? limit 10;mysql>select photo_id,count(*) from photo_comment where photo_id in(?)group by photo_id;mysql>show profiles;mysql>show profile cpu,block io for query ?;           

複制

如上系列操作,是分析 SQL 語句的執行計劃和性能損耗情況。

Schema 設計對系統性能影響

論壇文章案例:假設現在是高并發的一個論壇系統。

你需要考慮高并發的論壇最高的并發在哪裡?

可能最高的并發是檢視文章标題清單,現在往往文章标題後面會跟一個作者的昵稱。 然而根據需求文章标題(作者昵稱),這裡需要關聯(這裡就需要有一個 join 查詢)。

但是由于高并發業務盡量避免使用關聯查詢, 盡量走單表查詢,那此時就會在文章表備援作者的昵稱,違反了範式設計,但是卻提高了系統性能和 QPS。

關于 Schema 設計大多秉承的基礎是基于範式設計,然而真實系統中其實個人總結有如下建立:

  1. 短小、精簡(字段選型、表列數、char(N)、varchar(N) 等)
  2. 字段備援
  3. 大小字段拆分(text、varchar(255) 等)
  4. 單表行數拆分

最終的目的就是:表小、行小、字段小

硬體環境對資料庫的性能的影響

資料庫是存取資料的地方,是以資料庫主機的 IO 性能肯定是需要最優先考慮的一個因素,這一點不管是什麼類型的資料庫應用都是适用的。

在主機中決定 IO 性能部件主要由磁盤和記憶體所決定,當然也包括各種與 IO 相關的闆卡。

如何去選擇具體的硬體,一般要基于業務是 OLTP 還是 OLAP,這樣你才能選擇适合的資料庫或對應的存儲引擎。

  • OLTP系統:一般并發量大,整體資料量多,每次通路資料較少,通路資料比較離散, 有活躍資料并且比例不大。要大的記憶體活躍資料可以 Cache,通路頻繁每次通路資料少,那麼對磁盤的 IOPS 表現要好,吞吐量是次要的。并發高,CPU 要求高,網絡互動頻繁網絡裝置要求較高。
  • OLAP系統:一般資料統計類,大多選用商業資料庫,不過基于 Oracle 的大多費用昂貴,MySQL 也确實提供的 Inforbright 列式存儲的存儲引擎,其此類業務具有資料量大,并發通路不多,每次通路需要檢索的資料都比較多,通路集中,沒有明顯的活躍資料的特點,需要盡可能大的磁盤吞吐量,并發不多,CPU 要求不高。

總之:要根據自己系統的特性選擇更适合更廉價的硬體裝置。

總結

隻有了解哪些因素會影響資料庫的性能,才能結合業務去逐個優化和提升對應的性能,不管是存儲層面、硬體層面、資料層面等。