MySQL的主動優化和被動優化_MySQL“被動”性能優化匯總!

年少不知優化苦,遇坑方知優化難。 ——村口王大爺

本文內容導圖如下:

a0a8c5e822bd4093bd67ceb023b52528.png

我之前有很多文章都在講性能優化的問題,比如下面這些:

當然,本篇也是關于性能優化的,那性能優化就應該一把梭子嗎?還是要符合一些規范和原則呢?

020b08a77108ae782e4f86a3a6d7632c.png

所以,在開始之前(MySQL 優化),咱們先來聊聊性能優化的一些原則。

性能優化原則和分類

性能優化一般可以分為:主動優化

被動優化

所謂的主動優化是指不需要外力的推動而自發進行的一種行為,比如當服務沒有明顯的卡頓、宕機或者硬件指標異常的情況下,自我出發去優化的行為,就可以稱之為主動優化。

c92699669d94481ccdc1ef809f9d6849.png

而被動優化剛好與主動優化相反,它是指在發現了服務器卡頓、服務異常或者物理指標異常的情況下,才去優化的這種行為。

性能優化原則

無論是主動優化還是被動優化都要符合以下性能優化的原則:優化不能改變服務運行的邏輯,要保證服務的正確性;

優化的過程和結果都要保證服務的安全性;

要保證服務的穩定性,不能為了追求性能犧牲程序的穩定性。比如不能為了提高 Redis 的運行速度,而關閉持久化的功能,因為這樣在 Redis 服務器重啟或者掉電之后會丟失存儲的數據。

b0055cc54f4d00f4609ffe8cef5d0f08.png

以上原則看似都是些廢話,但卻給了我們一個啟發,那就是我們性能優化手段應該是:預防性能問題為主+被動優化為輔。

也就是說,我們應該以預防性能問題為主,在開發階段盡可能的規避性能問題,而在正常情況下,應盡量避免主動優化,以防止未知的風險(除非是為了 KPI,或者是閑的沒事),尤其對生產環境而言更是如此,最后才是考慮被動優化。PS:當遇到性能緩慢下降、或硬件指標緩慢增加的情況,如今天內存的占用率是 50%,明天是 70%,后天是 90% ,并且絲毫沒有收回的跡象時,我們應該提早發現并處理此類問題(這種情況也屬于被動優化的一種)。

MySQL 被動性能優化

所以我們本文會重點介紹 MySQL 被動性能優化的知識,根據被動性能優化的知識,你就可以得到預防性能問題發生的一些方法,從而規避 MySQL 的性能問題。

本文我們會從問題入手,然后考慮這個問題產生的原因以及相應的優化方案。我們在實際開發中,通常會遇到以下 3 個問題:單條 SQL 運行慢;

部分 SQL 運行慢;

整個 SQL 運行慢。

fd79bf973243b8f374c4489675b1444e.png

問題 1:單條 SQL 運行慢

問題分析

造成單條 SQL 運行比較慢的常見原因有以下兩個:未正常創建或使用索引;

表中數據量太大。

解決方案 1:創建并正確使用索引

索引是一種能幫助 MySQL 提高查詢效率的主要手段,因此一般情況下我們遇到的單條 SQL 性能問題,通常都是由于未創建或為正確使用索引而導致的,所以在遇到單條 SQL 運行比較慢的情況下,你首先要做的就是檢查此表的索引是否正常創建。

如果表的索引已經創建了,接下來就要檢查一下此 SQL 語句是否正常觸發了索引查詢,如果發生以下情況那么 MySQL 將不能正常的使用索引:在 where 子句中使用 != 或者 <> 操作符,查詢引用會放棄索引而進行全表掃描;

不能使用前導模糊查詢,也就是 '%XX' 或 '%XX%',由于前導模糊不能利用索引的順序,必須一個個去找,看是否滿足條件,這樣會導致全索引掃描或者全表掃描;

如果條件中有 or 即使其中有條件帶索引也不會正常使用索引,要想使用 or 又想讓索引生效,只能將 or 條件中的每個列都加上索引才能正常使用;

在 where 子句中對字段進行表達式操作。

因此你要盡量避免以上情況,除了正常使用索引之外,我們也可以使用以下技巧來優化索引的查詢速度:盡量使用主鍵查詢,而非其他索引,因為主鍵查詢不會觸發回表查詢;

查詢語句盡可能簡單,大語句拆小語句,減少鎖時間;

盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型;

用 exists 替代 in 查詢;

避免在索引列上使用 is null 和 is not null。回表查詢:普通索引查詢到主鍵索引后,回到主鍵索引樹搜索的過程,我們稱為回表查詢。

解決方案 2:數據拆分

當表中數據量太大時 SQL 的查詢會比較慢,你可以考慮拆分表,讓每張表的數據量變小,從而提高查詢效率。

1.垂直拆分

指的是將表進行拆分,把一張列比較多的表拆分為多張表。比如,用戶表中一些字段經常被訪問,將這些字段放在一張表中,另外一些不常用的字段放在另一張表中,插入數據時,使用事務確保兩張表的數據一致性。

垂直拆分的原則:把不常用的字段單獨放在一張表;

把 text,blob 等大字段拆分出來放在附表中;

經常組合查詢的列放在一張表中。

2.水平拆分

指的是將數據表行進行拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的數據拆成多張表來存放。

通常情況下,我們使用取模的方式來進行表的拆分,比如,一張有 400W 的用戶表 users,為提高其查詢效率我們把其分成 4 張表 users1,users2,users3,users4,然后通過用戶 ID 取模的方法,同時查詢、更新、刪除也是通過取模的方法來操作。

表的其他優化方案:使用可以存下數據最小的數據類型;

使用簡單的數據類型,int 要比 varchar 類型在 MySQL 處理簡單;

盡量使用 tinyint、smallint、mediumint 作為整數類型而非 int;

盡可能使用 not null 定義字段,因為 null 占用 4 字節空間;

盡量少用 text 類型,非用不可時最好考慮分表;

盡量使用 timestamp,而非 datetime;

單表不要有太多字段,建議在 20 個字段以內。

問題 2:部分 SQL 運行慢

問題分析

部分 SQL 運行比較慢,我們首先要做的就是先定位出這些 SQL,然后再看這些 SQL 是否正確創建并使用索引。也就是說,我們先要使用慢查詢工具定位出具體的 SQL,然后再使用問題 1 的解決方案處理慢 SQL。

解決方案:慢查詢分析

MySQL 中自帶了慢查詢日志的功能,開啟它就可以用來記錄在 MySQL 中響應時間超過閥值的語句,具體指運行時間超過 long_query_time 值的 SQL,則會被記錄到慢查詢日志中。long_query_time 的默認值為 10,意思是運行 10S 以上的語句。默認情況下,MySQL 數據庫并不啟動慢查詢日志,需要我們手動來設置這個參數,如果不是調優需要的話,一般不建議啟動該參數,因為開啟慢查詢日志會給 MySQL 服務器帶來一定的性能影響。慢查詢日志支持將日志記錄寫入文件,也支持將日志記錄寫入數據庫表。

使用 mysql> show variables like '%slow_query_log%'; 來查詢慢查詢日志是否開啟,執行效果如下圖所示:

f032a5431f327f068cbf08de903afcc9.png

slow_query_log 的值為 OFF 時,表示未開啟慢查詢日志。

開啟慢查詢日志

開啟慢查詢日志,可以使用如下 MySQL 命令:mysql> set global slow_query_log=1

不過這種設置方式,只對當前數據庫生效,如果 MySQL 重啟也會失效,如果要永久生效,就必須修改 MySQL 的配置文件 my.cnf,配置如下:slow_query_log =1

slow_query_log_file=/tmp/mysql_slow.log

當你開啟慢查詢日志之后,所有的慢查詢 SQL 都會被記錄在 slow_query_log_file 參數配置的文件內,默認是 /tmp/mysql_slow.log 文件,此時我們就可以打開日志查詢到所有慢 SQL 進行逐個優化。

問題 3:整個 SQL 運行慢

問題分析

當出現整個 SQL 都運行比較慢就說明目前數據庫的承載能力已經到了峰值,因此我們需要使用一些數據庫的擴展手段來緩解 MySQL 服務器了。

解決方案:讀寫分離

一般情況下對數據庫而言都是“讀多寫少”,換言之,數據庫的壓力多數是因為大量的讀取數據的操作造成的,我們可以采用數據庫集群的方案,使用一個庫作為主庫,負責寫入數據;其他庫為從庫,負責讀取數據。這樣可以緩解對數據庫的訪問壓力。

MySQL 常見的讀寫分離方案有以下兩種:

1.應用層解決方案

可以通過應用層對數據源做路由來實現讀寫分離,比如,使用 SpringMVC + MyBatis,可以將 SQL 路由交給 Spring,通過 AOP 或者 Annotation 由代碼顯示的控制數據源。

優點:路由策略的擴展性和可控性較強。

缺點:需要在 Spring 中添加耦合控制代碼。

2.中間件解決方案

通過 MySQL 的中間件做主從集群,比如:Mysql Proxy、Amoeba、Atlas 等中間件都能符合需求。

優點:與應用層解耦。

缺點:增加一個服務維護的風險點,性能及穩定性待測試,需要支持代碼強制主從和事務。

擴展知識:SQL 語句分析

在 MySQL 中我們可以使用 explain 命令來分析 SQL 的執行情況,比如:explain select * from t where id=5;

如下圖所示:

3d7fc037d6ac971a69238468312100aa.png

其中:id — 選擇標識符,id 越大優先級越高,越先被執行;

select_type — 表示查詢的類型;

table — 輸出結果集的表;

partitions — 匹配的分區;

type — 表示表的連接類型;

possible_keys — 表示查詢時,可能使用的索引;

key — 表示實際使用的索引;

key_len — 索引字段的長度;

ref— ?列與索引的比較;

rows — 大概估算的行數;

filtered — 按表條件過濾的行百分比;

Extra — 執行情況的描述和說明。

其中最重要的就是 type 字段,type 值類型如下:all — 掃描全表數據;

index — 遍歷索引;

range — 索引范圍查找;

index_subquery — 在子查詢中使用 ref;

unique_subquery — 在子查詢中使用 eq_ref;

ref_or_null — 對 null 進行索引的優化的 ref;

fulltext — 使用全文索引;

ref — 使用非唯一索引查找數據;

eq_ref — 在 join 查詢中使用主鍵或唯一索引關聯;

const — 將一個主鍵放置到 where 后面作為條件查詢, MySQL 優化器就能把這次查詢優化轉化為一個常量,如何轉化以及何時轉化,這個取決于優化器,這個比 eq_ref 效率高一點。

總結

本文我們介紹了 MySQL 性能優化的原則和分類,MySQL 的性能優化可分為:主動優化和被動優化,但無論何種優化都要保證服務的正確性、安全性和穩定性。它帶給我們的啟發是應該采用:預防 + 被動優化的方案來確保 MySQL 服務器的穩定性,而被動優化常見的問題是:單條 SQL 運行慢;

部分 SQL 運行慢;

整個 SQL 運行慢。

因此我們給出了每種被動優化方案的問題分析和解決方案,希望本文可以幫助到你。關注公眾號「Java中文社群」獲取更多精彩內容。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372191.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372191.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372191.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python2

一、管理庫的安裝 安裝pip 提示報錯&#xff1a;安裝pip提示No module named setuptools Windows環境下Python默認是沒有安裝setuptools這個模塊的&#xff0c;這也是一個第三方模塊。下載地址為http://pypi.python.org/pypi/setuptools。下載后直接運行ez_setup.py 參考地址&…

Java Mybatis

Mybatis轉載于:https://www.cnblogs.com/leading-index/p/6853031.html

Java例外:java lang NoSuchMethodError

如果查看錯誤消息java.lang.NoSuchMethodError&#xff0c;您可能會理解Java虛擬機正在嘗試向我們表明您調用的方法在類或接口中不可用。 您還可能在執行沒有公共static void main&#xff08;&#xff09;方法的類時拋出此錯誤。要了解其背后的原因&#xff0c;請閱讀本文。 …

【圖】最短路徑——Floyed算法和Dijkstra算法

最短路徑問題(floyed.cpp dijkstra.cpp) 題目描述平面上有n個點(n<100)&#xff0c;每個點的坐標均在-10000&#xff5e;10000之間。其中的一些點之間有連線。若有連線&#xff0c;則表示可從一個點到達另一個點&#xff0c;即兩點間有通路&#xff0c;通路的距離為兩點間的…

java的empty_Java Stack empty()方法與示例

堆棧類empty()方法empty()方法在java.util包中可用。empty()方法用于檢查此堆棧是否為空。empty()方法是一個非靜態方法&#xff0c;只能通過類對象訪問&#xff0c;如果嘗試使用類名稱訪問該方法&#xff0c;則會收到錯誤消息。在檢查空狀態時&#xff0c;empty()方法不會引發…

Java并發– CyclicBarrier示例

Java中的CyclicBarrier是JDK 5中java.util.Concurrent包中引入的同步器&#xff0c;以及其他并發實用程序&#xff08;如Counting Semaphore &#xff0c; BlockingQueue &#xff0c; ConcurrentHashMap等&#xff09;。CyclicBarrier與CountDownLatch類似&#xff0c;我們在上…

java i o總結_Java I/O 總結

一、IO流的三種分類方式1.按流的方向分為&#xff1a;輸入流和輸出流2.按流的數據單位不同分為&#xff1a;字節流和字符流3.按流的功能不同分為&#xff1a;節點流和處理流二、IO流的四大抽象類&#xff1a;字符流&#xff1a;Reader Writer字節流&#xff1a;InputStream(讀數…

try...catch 語句

一般情況下&#xff0c;我們很少用到 try...catch 語句&#xff0c;但是有時候為了測試代碼中的錯誤&#xff0c;也有可能會用到。小白我也在工作中用到過。那么好的程序設計&#xff0c;什么時候會用到呢&#xff1f; try...catch 一般用來捕獲宿主對象或者ECMAScript拋出的異…

用Mockito回答

在編寫單元測試時 &#xff0c;必須牢記不要依賴外部組件。 為了避免這種情況&#xff0c;我們使用了模擬框架&#xff0c;對我來說&#xff0c;最容易使用的是Mockito 。 在本文中&#xff0c;我們將看到在Mockito中使用的一種“高級”技術&#xff0c;可以使用Answer接口在模…

java三板斧_Java 枚舉使用三板斧

Java 枚舉使用三板斧1 定義public enum CountryEnums {ONE(1,"韓"),TWO(2,"魏"),THREE(3,"楚"),FOUR(4,"燕"),FIVE(5,"趙"),SIX(6,"齊");private Integer retCode;private String retMsg;// 枚舉的構造方法是 pri…

假裝這些是MyEclipse的快捷鍵(1)

Java快捷鍵 Alt / 代碼自動補全Alt Shift S 功能菜單 Ctrl 1 代碼自動修正Ctrl / 單行注釋/取消Ctrl O 查看類的所有方法Ctrl T 查看類的集成架構圖Ctrl Shift / 多行注釋Ctrl Shift \ 取消多行注釋Ctrl Shift F 代碼格式化轉載于:https://www.cnblogs.com/swordt…

JasperReports JSF插件用例–簡單列表報告

這是JasperReports JSF插件系列的第一篇“用例文章” &#xff0c;我將專注于一個簡單的需求&#xff0c;并且我將進一步深入。 起點是我們已經為圖書商店完成的項目設置&#xff0c;我將向其中添加一個列表&#xff0c;其中包含在數據庫中注冊的其他圖書&#xff0c;該列表也將…

2016.10.17先占坑

2016.10.17先占坑轉載于:https://www.cnblogs.com/amurzet/p/5978986.html

ER圖流程圖

ER圖&#xff1a;ER圖分為實體、屬性、關系三個核心部分。實體是長方形體現&#xff0c;而屬性則是橢圓形&#xff0c;關系為菱形。 圖書館管理系統流程圖&#xff08;圖片源于網上&#xff09;&#xff1a;對于程序員來說&#xff0c;我們要知道&#xff1a;整個系統中&#x…

php源碼仿三一重工,織夢仿三一重工業大學氣企業網站php源碼

★模板引薦★源碼稱呼&#xff1a;仿三一重工業大學氣企業網站php源碼仿三一重工業大學氣企業網站php源碼&#xff0c;嘗試完備無錯&#xff0c;兼容合流欣賞器。模板包括安置證明&#xff0c;并包括嘗試數據。本模板鑒于DEDECms 5.7 GBK安排&#xff0c;須要 UTF-8版本的請本人…

接觸Jenkins(Hudson)API,第2部分

這篇文章從本教程的第1部分繼續。 已經快一年了&#xff0c;但是我終于有時間重新審視我為與Jenkins api交互而編寫的一些代碼。 我已經使用了部分工作來幫助管理許多Jenkins構建服務器&#xff0c;主要是保持插件同步以及將作業從一臺機器移動到另一臺機器。 在本文中&#xf…

php樹莓派魔鏡,用樹莓派和顯示器制作一面“魔鏡”

所需要的材料一臺顯示器一塊和顯示器大小相同的雙面鏡一些2*4米的細木條樹莓派機器必要組件(電源、HDMI線、usb無線網卡、鍵盤)木工工具(鋸子、磨砂機、螺絲刀)螺絲、液態釘子選一個合適的顯示器鏡子的大小完全由顯示器的類型和大小決定&#xff0c;所以我希望得到一個盡量大的…

【數字圖像處理】[3]--直方圖規范化

【數字圖像處理】[3]--直方圖規范化直方圖規范化出現的原因是因為直方圖均衡只能產生出固定的圖像&#xff0c;不滿足于需求&#xff0c;有時我們需要讓直方圖變成特定的直方圖&#xff0c;于是有了直方圖規范化原理&#xff1a;可能只看公式沒什么感覺&#xff0c;我們來舉一個…

JavaFX 2.0布局窗格– GridPane

毫無疑問&#xff0c; GridPane是JavaFX 2.0中功能最強大&#xff0c;最靈活的布局窗格。 它在由行和列組成的靈活網格中布置其子項&#xff0c;與Swing的GridBagLayout或HTML的表格模型非常相似。 這種方法使該窗格非常適合于任何形式的表單&#xff08;例如網站上的聯系表單&…

leecode 題解 || Merge k Sorted Lists 問題

problem&#xff1a; Merge k sorted linked lists and return it as one sorted list.Analyze and describe its complexity.Tags Divide and Conquer Linked List Heap合并K個已序單鏈表 thinking&#xff1a; &#xff08;1&#xff09;題目沒有要求不能夠新開ListNode,所以…