主頁 > 資料庫 > MySQL性能優化淺析及線上案例

MySQL性能優化淺析及線上案例

2023-01-20 07:27:05 資料庫

作者:京東健康 孟飛

1、 資料庫性能優化的意義

業務發展初期,資料庫中量一般都不高,也不太容易出一些性能問題或者出的問題也不大,但是當資料庫的量級達到一定規模之后,如果缺失有效的預警、監控、處理等手段則會對用戶的使用體驗造成影響,嚴重的則會直接導致訂單、金額直接受損,因而就需要時刻關注資料庫的性能問題,

2、 性能優化的幾個常見措施

資料庫性能優化的常見手段有很多,比如添加索引、分庫分表、優化連接池等,具體如下:

序號 型別 措施 說明
1 物理級別 提升硬體性能 將資料庫安裝到更高配置的服務器上會有立竿見影的效果,例如提高CPU配置、增加記憶體容量、采用固態硬碟等手段,在經費允許的范圍可以嘗試,
2 應用級別 連接池引數優化 我們大部分的應用都是使用連接池來托管資料庫的連接,但是大部分都是默認的配置,因而配置好超時時長、連接池容量等引數就顯得尤為重要, 1、 如果鏈接長時間被占用,新的請求無法獲取到新的連接,就會影響到業務, 2、 如果連接數設定的過小,那么即使硬體資源沒問題,也無法發揮其功效,之前公司做過一些壓測,但就是死活不達標,最后發現是由于連接數太小,
3 單表級別 合理運用索引 如果資料量較大,但是又沒有合適的索引,就會拖垮整個性能,但是索引是把雙刃劍,并不是說索引越多越好,而是要根據業務的需要進行適當的添加和使用, 缺失索引、重復索引、冗余索引、失控索引這幾類情況其實都是對系統很大的危害,
4 庫表級別 分庫分表 當資料量較大的時候,只使用索引就意義不大了,需要做好分庫分表的操作,合理的利用好磁區鍵,例如按照用戶ID、訂單ID、日期等維度進行磁區,可以減少掃描范圍,
5 監控級別 加強運維 針對線上的一些系統還需要進一步的加強監控,比如訂閱一些慢SQL日志,找到比較糟糕的一些SQL,也可以利用業務內一些通用的工具,例如druid組件等,

3、 MySQL底層架構

首先了解一下資料的底層架構,也有助于我們做更好優化,

一次查詢請求的執行程序

我們重點關注第二部分和第三部分,第二部分其實就是Server層,這層主要就是負責查詢優化,制定出一些執行計劃,然后呼叫存盤引擎給我們提供的各種底層基礎API,最終將資料回傳給客戶端,

4、MySQL索引構建程序

目前比較常用的是InnoDB存盤引擎,本文討論也是基于InnoDB引擎,我們一直說的加索引,那到底什么是索引、索引又是如何形成的呢、索引又如何應用呢?這個話題其實很大也很小,說大是因為他底層確實很復雜,說小是因為在大部分場景下程式員只需要添加索引就好,不太需要了解太底層原理,但是如果了解不透徹就會引發線上問題,因而本文平衡了大家的理解成本和知識深度,有一定底層原理介紹,但是又不會太過深入導致難以理解,

首先來做個實驗:

創建一個表,目前是只有一個主鍵索引

CREATE TABLE t1(

a int NOT NULL,

b int DEFAULT NULL,

c int DEFAULT NULL,

d int DEFAULT NULL,

e varchar(20) DEFAULT NULL,

PRIMARYKEY(a)

)ENGINE=InnoDB

插入一些資料:

insert into test.t1 values(4,3,1,1,'d');

insert into test.t1 values(1,1,1,1,'a');

insert into test.t1 values(8,8,8,8,'h');

insert into test.t1 values(2,2,2,2,'b');

insert into test.t1 values(5,2,3,5,'e');

insert into test.t1 values(3,3,2,2,'c');

insert into test.t1 values(7,4,5,5,'g');

insert into test.t1 values(6,6,4,4,'f');

MYSQL從磁盤讀取資料到記憶體是按照一頁讀取的,一頁默認是16K,而一頁的格式大概如下,

每一頁都包括了這么幾個內容,首先是頁頭、其次是頁目錄、還有用戶資料區域,

1)剛才插入的幾條資料就是放到這個用戶資料區域的,這個是按照主鍵依次遞增的單向鏈表,

2)頁目錄這個是用來指向具體的用戶資料區域,因為當用戶資料區域的資料變多的時候也就會形成分組,而頁目錄就會指向不同的分組,利用二分查找可以快速的定位資料,

當資料量變多的時候,那么這一頁就裝不下這么多資料,就要分裂頁,而每頁之間都會雙向鏈接,最終形成一個雙向鏈表,

頁內的單向鏈表是為了查找快捷,而頁間的雙向鏈表是為了在做范圍查詢的時候提效,下圖為示意圖,其中其二頁和第三頁是復制的第一頁,并不真實,

而如果資料還繼續累加,光這幾個頁也不夠了,那就逐步的形成了一棵樹,也就是說索引B-Tree是隨著資料的積累逐步構建出來的,

最下邊的一層叫做葉子節點,上邊的叫做內節點,而葉子節點中存盤的是全量資料,這樣的樹就是聚簇索引,一直有同學的理解是說索引是單獨一份而資料是一份,其實MySQL中有一個原則就是資料即索引、索引即資料,真實的資料本身就是存盤在聚簇索引中的,所謂的回表就是回的聚簇索引

但是我們也不一定每次都按照主鍵來執行SQL陳述句,大部分情況下都是按照一些業務欄位來,那就會形成別的索引樹,例如,如果按照b,c,d來創建的索引就會長這樣,

推薦1個網站,可以可視化的查看一些演算法原型:

目錄:

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

B+樹

https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

而在MySQL官網上介紹的索引的葉子節點是雙向鏈表,

關于索引結構的小結:

對于B-Tree而言,葉子節點是沒有鏈接的,而B+Tree索引是單向鏈表,但是MySQL在B+Tree的基礎之上加以改進,形成了雙向鏈表,雙向的好處是在處理> <,between and等'范圍查詢'語法時可以得心應手,

5、MySQL索引的一些使用規范

1、 只為用于搜索、排序或分組的列創建索引,

重點關注where陳述句后邊的情況

2、 當列中不重復值的個數在總記錄條數中的占比很大時,才為列建立索引,

例如手機號、用戶ID、班級等,但是比如一張全校學生表,每條記錄是一名學生,where陳述句是查詢所有’某學校‘的學生,那么其實也不會提高性能,

3、 索引列的型別盡量小,

無論是主鍵還是索引列都盡量選擇小的,如果很大則會占據很大的索引空間,

4、 可以只為索引列前綴創建索引,減少索引占用的存盤空間,

alter table single_table add index idx_key1(key1(10))

5、 盡量使用覆寫索引進行查詢,以避免回表操作帶來的性能損耗,

select key1 from single_table order by key1

6、 為了盡可能的少的讓聚簇索引發生頁面分裂的情況,建議讓主鍵自增,

7、 定位并洗掉表中的冗余和重復索引,

冗余索引:

單列索引:(欄位1)

聯合索引:(欄位1 欄位2)

重復索引:

在一個欄位上添加了普通索引、唯一索引、主鍵等多個索引

6、 執行計劃

其中常用的是:

possible_keys: 可能用到的索引

key: 實際使用的索引

rows:預估的需要讀取的記錄條數

7、 線上案例

案例1:

在建設互聯網醫院系統中,問診單表當時量級23萬左右,其中有一個business_id字串欄位,這個欄位用來記錄外部訂單的ID,并且在該欄位上也加了索引,但是'根據該ID查詢詳情'的SQL陳述句卻總是時好時壞,性能不穩定,快則10ms,慢則2秒左右,SQL大體如下:

select 欄位1、欄位2、欄位3 from nethp_diag where business_Id = ?

因為business_id是記錄第三方系統的訂單ID,為了兼容不同的第三方系統,因而設計成了字串型別,但如果傳入的是一個數字型別是無法使用索引的,因為MySQL只能將字串轉數字,而不能將數字轉字串,由于外部的ID有的是數字有的是字串,因而導致索引一會可以走到,一會走不到,最終導致了性能的不穩定,

案例2:

在某次大促的當天,突然接到DBA運維的報警,說資料庫突然流量激增,CPU也打到100%了,影響了部分線上功能和體驗,遇到這種情況當時大部分人都比較緊張,下圖為當時的資料庫流量情況:

相關SQL陳述句:

當時的索引情況

當時的執行計劃

其實在patientId和doctor_pin兩個欄位上是有索引的,但是由于線上情況的改變,導致test判斷沒有進入,這樣的通用查詢導致這兩個欄位沒有設定上,進而導致了資料庫掃描的量激增,對資料庫產生了很大壓力,

案例3:

2020年某日上午收到資料庫CPU例外報警,對線上有一定的影響,后續檢查資料庫CPU情況如下,從7點51分開始,CPU從8%瞬間達到99.92%,絲毫沒有給程式員留任何情面,

當時的SQL陳述句:

select rx_id, rx_create_time from nethp_rx_info where rx_status = 5 and status = 1 and rx_product_type = 0 and (parent_rx_id = 0 or parent_rx_id is null) and business_type != 7 and vender_id = 8888 order by rx_create_time asc limit 1;

當時的索引情況:

PRIMARY KEY (id), UNIQUE KEY uniq_rx_id (rx_id), KEY idx_diag_id (diag_id), KEY idx_doctor_pin (doctor_pin) USING BTREE, KEY idx_rx_storeId (store_id), KEY idx_parent_rx_id (parent_rx_id) USING BTREE, KEY idx_rx_status (rx_status) USING BTREE, KEY idx_doctor_status_type (doctor_pin, rx_status, rx_type), KEY idx_business_store (business_type, store_id), KEY idx_doctor_pin_patientid (patient_id, doctor_pin) USING BTREE, KEY idx_rx_create_time (rx_create_time)

當時這張表量級2000多萬,而當這條慢SQL執行較少的時候,資料庫的CPU也就下來了,恢復到了49.91%,基本可以恢復線上業務,從而表象就是線上間歇性的一會可以開方一會不可以,這條SQL當時總共執行了230次,當時的CPU情況也是忽高忽低,伴隨這條SQL陳述句的執行情況,從而最終證明CPU的飆升是由于這條慢SQL,當線上業務邏輯復雜的時候,你很難第一時間知道到底是由于那條SQL引起的,這個就需要對業務非常熟悉,對SQL很熟悉,否則就會白白浪費大量的排查時間,

最后的排查結果:

在頭天晚上的時候添加了一條索引rx_create_time,當時沒事,但是第二天卻出了事故,

加索引前后走的索引不同,一個是走的rx_status(處方審核狀態)單列索引,一個是走的rx_create_time(處方提交事件)單列索引,這個就要回到業務,因為處方狀態是個列舉,且列舉范圍不到10個,也就說線上29,000,000的資料量也就是被分成了不到10份,rx_status=5的值是其中一份,因而通過這個索引就可以命中很多行,這是業務規則,再套用MySQL的特性,主要是以下幾條:

1、沒加新索引rx_create_time的時候,由于order by后邊沒有索引,就看where條件中是否有合適的索引,查詢選擇器選定rx_status這個單列索引,而rx_status=5這個條件下限制的資料行在索引中是連續,即使需要的rx_id不在索引中,再回主鍵聚簇索引也來得及,由于order by后邊沒有索引,所以走磁盤級別的排序filesort,高峰積壓的時候處方就1萬到2萬,跑到了100ms,白天低谷的時候幾百單也就20ms,

2、新加索引之后,就分兩種情況:

2.1、加索引是在晚上,當前命中的行數比較少,由于當天晚上的時候待審核的處方確實很少,也就是rx_status=5的確實很少,查詢優化器感覺反正沒多少行,排序不重要,因而就還是選擇rx_status索引,

2.2、第二天白天,待審核的處方數量很多了(rx_status=5的資料量多了),當時可以命中幾萬資料,如果當前命中的行數比較多,查詢優化器就開始算成本,感覺排序的成本會更高,那就優先保排序吧,所以就選擇rx_create_time這個欄位,但是這個索引樹上沒有別的索引欄位的資訊,沒辦法,幾乎每條資料都要回表,進而引發了災難,

8、 推薦用書

這本書以一種詼諧幽默的風格寫了MySQL的一些運行機制,非常適合閱讀,理解成本大幅降低,

https://item.jd.com/13009316.html

https://item.jd.com/10066181997303.html

9、一些感悟

關于資料庫的性能優化其實是一個很復雜的大課題,很難通過一篇帖子講的很全面和深刻,這也就是為什么我的標題是‘淺析’,程式員的成長一定是要付出代價和成本,因為只有真的在一線切身體會到當時的緊張和壓力,對于一件事情才能印象深刻,但反之也不能太過于強調代價,如果可以通過一些別人的分享就可以規避一些自己業務的問題和錯誤的代價也是好的,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/542309.html

標籤:其他

上一篇:MySQL必知必會第十三章-分組資料

下一篇:MySQL必知必會第十三章-分組資料

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more