共計 4422 個字符,預計需要花費 12 分鐘才能閱讀完成。
如何解決 MySQL 查詢速度慢與性能差的問題,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
一、什么影響了數據庫查詢速度
1.1 影響數據庫查詢速度的四個因素
1.2 風險分析
QPS:Queries Per Second 意思是“每秒查詢率”,是一臺服務器每秒能夠相應的查詢次數,是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。
TPS:是 TransactionsPerSecond 的縮寫,也就是事務數 / 秒。它是軟件測試結果的測量單位。客戶機在發送請求時開始計時,收到服務器響應后結束計時,以此來計算使用的時間和完成的事務個數。
Tips:最好不要在主庫上數據庫備份,大型活動前取消這樣的計劃。
效率低下的 sql:超高的 QPS 與 TPS。
大量的并發:數據連接數被占滿(max_connection 默認 100,一般把連接數設置得大一些)。
并發量: 同一時刻數據庫服務器處理的請求數量
超高的 CPU 使用率:CPU 資源耗盡出現宕機。
磁盤 IO:磁盤 IO 性能突然下降、大量消耗磁盤性能的計劃任務。解決:更快磁盤設備、調整計劃任務、做好磁盤維護。
1.3 網卡流量:如何避免無法連接數據庫的情況
減少從服務器的數量(從服務器會從主服務器復制日志)
進行分級緩存(避免前端大量緩存失效)
避免使用 select * 進行查詢
分離業務網絡和服務器網絡
1.4 大表帶來的問題(重要)
1.4.1 大表的特點
記錄行數巨大,單表超千萬
表數據文件巨大,超過 10 個 G
1.4.2 大表的危害
1. 慢查詢:很難在短時間內過濾出需要的數據
查詢字區分度低 – 要在大數據量的表中篩選出來其中一部分數據會產生大量的磁盤 io – 降低磁盤效率
2. 對 DDL 影響:
建立索引需要很長時間:
MySQL -v 5.5 建立索引會鎖表
MySQL -v =5.5 建立索引會造成主從延遲(mysql 建立索引,先在組上執行,再在庫上執行)
修改表結構需要長時間的鎖表:會造成長時間的主從延遲(480 秒延遲)
1.4.3 如何處理數據庫上的大表
分庫分表把一張大表分成多個小表
難點:
分表主鍵的選擇
分表后跨分區數據的查詢和統計
1.5 大事務帶來的問題(重要)
1.5.1 什么是事務
1.5.2 事務的 ACID 屬性
1. 原子性(atomicity):全部成功,全部回滾失敗。銀行存取款。
2. 一致性(consistent):銀行轉賬的總金額不變。
3. 隔離性(isolation):
隔離性等級:
未提交讀(READ UNCOMMITED) 臟讀, 兩個事務之間互相可見;
已提交讀 (READ COMMITED) 符合隔離性的基本概念, 一個事務進行時,其它已提交的事物對于該事務是可見的,即可以獲取其它事務提交的數據。
可重復讀(REPEATABLE READ) InnoDB 的默認隔離等級。事務進行時,其它所有事務對其不可見,即多次執行讀,得到的結果是一樣的!
可串行化(SERIALIZABLE) 在讀取的每一行數據上都加鎖,會造成大量的鎖超時和鎖征用,嚴格數據一致性且沒有并發是可使用。
查看系統的事務隔離級別:show variables like %iso%
開啟一個新事務:begin;
提交一個事務:commit;
修改事物的隔離級別:set session tx_isolation= read-committed
4. 持久性(DURABILITY):從數據庫的角度的持久性,磁盤損壞就不行了
redo log 機制保證事務更新的一致性和持久性
1.5.3 大事務
運行時間長,操作數據比較多的事務;
風險:鎖定數據太多,回滾時間長,執行時間長。
鎖定太多數據,造成大量阻塞和鎖超時;
回滾時所需時間比較長,且數據仍然會處于鎖定;
如果執行時間長,將造成主從延遲,因為只有當主服務器全部執行完寫入日志時,從服務器才會開始進行同步,造成延遲。
解決思路:
避免一次處理太多數據,可以分批次處理;
移出不必要的 SELECT 操作,保證事務中只有必要的寫操作。
二、什么影響了 MySQL 性能(非常重要)
2.1 影響性能的幾個方面
服務器硬件。
服務器系統(系統參數優化)。
存儲引擎。
MyISAM:不支持事務,表級鎖。
InnoDB: 支持事務,支持行級鎖,事務 ACID。
數據庫參數配置。
數據庫結構設計和 SQL 語句。(重點優化)
2.2 MySQL 體系結構
分三層:客戶端 - 服務層 - 存儲引擎
MySQL 是插件式的存儲引擎,其中存儲引擎分很多種。只要實現符合 mysql 存儲引擎的接口,可以開發自己的存儲引擎!
所有跨存儲引擎的功能都是在服務層實現的。
MySQL 的存儲引擎是針對表的,不是針對庫的。也就是說在一個數據庫中可以使用不同的存儲引擎。但是不建議這樣做。
2.3 InnoDB 存儲引擎
MySQL5.5 及之后版本默認的存儲引擎:InnoDB。
2.3.1 InnoDB 使用表空間進行數據存儲。
show variables like innodb_file_per_table
如果 innodb_file_per_table 為 ON 將建立獨立的表空間,文件為 tablename.ibd;
如果 innodb_file_per_table 為 OFF 將數據存儲到系統的共享表空間,文件為 ibdataX(X 為從 1 開始的整數);
.frm:是服務器層面產生的文件,類似服務器層的數據字典,記錄表結構。
2.3.2 (MySQL5.5 默認)系統表空間與 (MySQL5.6 及以后默認) 獨立表空間
1.1 系統表空間無法簡單的收縮文件大小,造成空間浪費,并會產生大量的磁盤碎片。
1.2 獨立表空間可以通過 optimeze table 收縮系統文件,不需要重啟服務器也不會影響對表的正常訪問。
2.1 如果對多個表進行刷新時,實際上是順序進行的,會產生 IO 瓶頸。
2.2 獨立表空間可以同時向多個文件刷新數據。
強烈建立對 Innodb 使用獨立表空間,優化什么的更方便,可控。
2.3.3 系統表空間的表轉移到獨立表空間中的方法
1、使用 mysqldump 導出所有數據庫數據 (存儲過程、觸發器、計劃任務一起都要導出) 可以在從服務器上操作。
2、停止 MYsql 服務器,修改參數(my.cnf 加入 innodb_file_per_table),并刪除 Inoodb 相關文件(可以重建 Data 目錄)。
3、重啟 MYSQL,并重建 Innodb 系統表空間。
4、重新導入數據。
或者 Alter table 同樣可以的轉移,但是無法回收系統表空間中占用的空間。
2.4 InnoDB 存儲引擎的特性
2.4.1 特性一:事務性存儲引擎及兩個特殊日志類型:Redo Log 和 Undo Log
Innodb 是一種事務性存儲引擎。
完全支持事務的 ACID 特性。
支持事務所需要的兩個特殊日志類型:Redo Log 和 Undo Log
Redo Log:實現事務的持久性(已提交的事務)。
Undo Log:未提交的事務,獨立于表空間,需要隨機訪問,可以存儲在高性能 io 設備上。
Undo 日志記錄某數據被修改前的值,可以用來在事務失敗時進行 rollback;Redo 日志記錄某數據塊被修改后的值,可以用來恢復未寫入 data file 的已成功事務更新的數據。
2.4.2 特性二:支持行級鎖
InnoDB 支持行級鎖。
行級鎖可以最大程度地支持并發。
行級鎖是由存儲引擎層實現的。
2.5 什么是鎖
2.5.1 鎖
2.5.2 鎖類型
2.5.3 鎖的粒度
MySQL 的事務支持不是綁定在 MySQL 服務器本身,而是與存儲引擎相關
將 table_name 加表級鎖命令:lock table table_name write; 寫鎖會阻塞其它用戶對該表的 lsquo; 讀寫 rsquo; 操作,直到寫鎖被釋放:unlock tables;
鎖的開銷越大,粒度越小,并發度越高。
表級鎖通常是在服務器層實現的。
行級鎖是存儲引擎層實現的。innodb 的鎖機制,服務器層是不知道的
2.5.4 阻塞和死鎖
(1)阻塞是由于資源不足引起的排隊等待現象。
(2)死鎖是由于兩個對象在擁有一份資源的情況下申請另一份資源,而另一份資源恰好又是這兩對象正持有的,導致兩對象無法完成操作,且所持資源無法釋放。
2.6 如何選擇正確的存儲引擎
參考條件:
事務
備份(Innobd 免費在線備份)
崩潰恢復
存儲引擎的特有特性
總結:Innodb 大法好。
注意: 盡量別使用混合存儲引擎,比如回滾會出問題在線熱備問題。
2.7 配置參數
2.7.1 內存配置相關參數
確定可以使用的內存上限。
內存的使用上限不能超過物理內存,否則容易造成內存溢出;(對于 32 位操作系統,MySQL 只能試用 3G 以下的內存。)
確定 MySQL 的每個連接單獨使用的內存。
sort_buffer_size #定義了每個線程排序緩存區的大小,MySQL 在有查詢、需要做排序操作時才會為每個緩沖區分配內存(直接分配該參數的全部內存);join_buffer_size #定義了每個線程所使用的連接緩沖區的大小,如果一個查詢關聯了多張表,MySQL 會為每張表分配一個連接緩沖,導致一個查詢產生了多個連接緩沖;read_buffer_size #定義了當對一張 MyISAM 進行全表掃描時所分配讀緩沖池大小,MySQL 有查詢需要時會為其分配內存,其必須是 4k 的倍數;read_rnd_buffer_size #索引緩沖區大小,MySQL 有查詢需要時會為其分配內存,只會分配需要的大小。
注意:以上四個參數是為一個線程分配的,如果有 100 個連接,那么需要 times;100。
MySQL 數據庫實例:
①MySQL 是單進程多線程(而 oracle 是多進程),也就是說 MySQL 實例在系統上表現就是一個服務進程,即進程;
②MySQL 實例是線程和內存組成,實例才是真正用于操作數據庫文件的;
一般情況下一個實例操作一個或多個數據庫; 集群情況下多個實例操作一個或多個數據庫。
如何為緩存池分配內存:
Innodb_buffer_pool_size,定義了 Innodb 所使用緩存池的大小,對其性能十分重要,必須足夠大,但是過大時,使得 Innodb 關閉時候需要更多時間把臟頁從緩沖池中刷新到磁盤中;
總內存 -(每個線程所需要的內存 * 連接數)- 系統保留內存
key_buffer_size,定義了 MyISAM 所使用的緩存池的大小,由于數據是依賴存儲操作系統緩存的,所以要為操作系統預留更大的內存空間;
select sum(index_length) from information_schema.talbes where engine= myisam
注意:即使開發使用的表全部是 Innodb 表,也要為 MyISAM 預留內存,因為 MySQL 系統使用的表仍然是 MyISAM 表。
max_connections 控制允許的 *** 連接數,一般 2000 更大。
不要使用外鍵約束保證數據的完整性。
2.8 性能優化順序
從上到下:
看完上述內容,你們掌握如何解決 MySQL 查詢速度慢與性能差的問題的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注丸趣 TV 行業資訊頻道,感謝各位的閱讀!