2020重新出發,MySql基礎,效能優化

夜雨流雲發表於2020-09-02

@

MySQL效能優化

應用開發過程中,由於初期資料量小,開發人員更重視功能上的實現,但是當應用系統正式上線後,隨著生產資料量的急劇增長,資料庫開始顯露效能問題,對生產的影響也越來越大,因此我們必須對它們進行優化。

效能優化是通過某些有效的方法提高 MySQL 資料庫的效能,主要是為了使 MySQL 資料庫執行速度更快、佔用的磁碟空間更小。

MySQL效能優化簡述

簡而言之,效能優化就是在不影響系統能正確執行的前提下,執行速度更快,完成特定功能所需的時間更短。

我們可以通過某些有效的方法來提高 MySQL 資料庫的效能,目的是讓 MySQL 資料庫的執行速度更快、佔用的磁碟空間更小。

效能優化包括很多方面,例如優化查詢速度、優化更新速度和優化 MySQL 伺服器等。通過不同的優化方式達到提高 MySQL 資料庫效能的目的。優化資料庫是資料庫管理員和開發人員的必備技能。

MySQL 資料庫的使用者和資料非常少時,很難判斷資料庫效能的好壞。只有當長時間執行,並且有大量使用者進行頻繁操作時,MySQL 資料庫的效能才能體現出來。

  • 例如,一個每天有幾萬使用者同時線上的大型網站,它的資料庫效能的優劣就很明顯。這麼多使用者同時連線 MySQL 資料庫,並且進行查詢、插入和更新的操作。如果 MySQL 資料庫的效能很差,很可能無法承受如此多使用者的同時操作。另外,如果使用者查詢一條記錄需要花費很長時間,那麼使用者很難會喜歡這個網站。

img

因此,為了提高 MySQL 資料庫的效能,需要進行一系列的優化措施。一方面是找出系統的瓶頸,提高 MySQL 資料庫整體的效能,另一方面需要合理的資料庫結構設計和引數調整,來提高使用者操作響應的速度,同時還要儘可能節省系統資源,以便系統可以提供更大負荷的服務。

例如,

  • 通過優化檔案系統,提高磁碟 I\O 的讀寫速度;
  • 通過優化作業系統排程策略,提高 MySQL 在高負荷情況下的負載能力;
  • 優化表結構、索引、查詢語句等使查詢響應更快。

如果 MySQL 資料庫中需要進行大量的查詢操作,那麼就需要對查詢語句進行優化。對於耗費時間的查詢語句進行優化,可以提高整體的查詢速度。如果連線 MySQL 資料庫的使用者很多,那麼就需要對 MySQL 伺服器進行優化。否則,大量的使用者同時連線 MySQL 資料庫,可能會造成資料庫系統崩潰。

系統的分析效率低下的 SQL 兩種方法:

使用 SHOW STATUS 命令

資料庫管理員可以使用 SHOW STATUS 語句查詢 MySQL 資料庫的效能引數,瞭解各種 SQL 的執行頻率。語法形式如下:

SHOW STATUS LIKE 'value';

其中,value 引數是常用的幾個統計引數,常用引數介紹如下:

  • Connections:連線 MySQL 伺服器的次數;
  • Uptime:MySQL 伺服器的上線時間;
  • Slow_queries:慢查詢的次數;
  • Com_select:查詢操作的次數;
  • Com_insert:插入操作的次數,對於批量插入操作,只累加一次;
  • Com_update:更新操作的次數;
  • Com_delete:刪除操作的次數。

以上引數針對於所有儲存引擎的表,下面幾個引數只針對 InnoDB 儲存引擎。

  • Innodb_rows_read:表示 SELECT 語句查詢的記錄數;
  • Innodb_rows_inserted:表示 INSERT 語句插入的記錄數;
  • Innodb_rows_updated:表示 UPDATE 語句更新的記錄數;
  • Innodb_rows_deleted:表示 DELETE 語句刪除的記錄數。

比如,需要查詢 MySQL 伺服器的連線次數,可以執行下面的 SHOW STATUS 語句:

SHOW STATUS LIKE 'Connections';

查詢其它引數的方法和以上引數的查詢方法相同。

通過以上幾個引數,可以很容易的瞭解當前資料庫的應用是以插入為主還是以查詢為主,以及各種型別的 SQL 語句的大致執行比例。然後根據分析結果,進行相應的效能優化。

使用慢查詢日誌

慢查詢次數引數可以結合慢查詢日誌,找出慢查詢語句,然後針對慢查詢語句進行表結構優化或者查詢語句優化。

MySQL 查詢分析器

查詢是資料庫中最頻繁的操作,提高查詢速度可以有效的提高 MySQL 資料庫的效能。

通過對查詢語句的分析,可以瞭解查詢語句的執行情況,找出查詢語句執行的瓶頸,從而優化查詢語句。在 MySQL 中,可以使用 EXPLAIN 和 DESCRIBE 獲取 MySQL 執行 SELECT 語句的資訊,來分析查詢語句

EXPLAIN 語句的基本語法如下:

EXPLAIN SELECT 語句;

“SELECT 語句”引數一般為資料庫查詢命令,如“SELECT * FROM tb_student”。通過 EXPLAIN 關鍵字可以分析後面 SELECT 語句的執行情況,並且能夠分析出所查詢表的一些內容。

EXPLAIN

例子:下面使用 EXPLAIN 語句來分析一個查詢語句。程式碼執行如下:

mysql> EXPLAIN SELECT * FROM tb_student \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 7
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.01 sec)

對以上結果中引數說明如下:

  1. id:表示 SELECT 語句的編號,也就是在整個查詢中 SELECT 的位置。如果在語句中沒子查詢或關聯查詢,只有唯一的 SELECT,每行都將顯示 1。否則,內層的 SELECT 語句一般會順序編號,對應於其在原始語句中的位置。
  2. select_type:表示 SELECT 語句的型別,該引數有以下幾個常用的取值:
    • SIMPLE:表示簡單查詢,其中不包括連線查詢和子查詢;
    • PRIMARY:表示主查詢,或者是最外層的查詢語句;
    • UNION:表示連線查詢的第二個或後面的查詢語句;
    • DEPENDENT UNION:連線查詢中的第 2 個或後面的 SELECT 語句,取決於外面的查詢;
    • UNION RESULT:連線查詢的結果;
    • SUBQUERY:子查詢中的第 1 個 SELECT 語句;
    • DEPENDENT SUBQUERY:子查詢中的第 1 個 SELECT 語句,取決於外面的查詢;
    • DERIVED:匯出表的 SELECT(FROM 子句的子查詢)
  3. table:表示查詢的表;
  4. partitions:
  5. type:表示表的連線型別。該引數有以下幾個常用的取值,範圍從 NULL 到 ALL。下面按照最佳型別到最差型別排序:
    • NULL:不用訪問表或者索引,直接就能得到結果;
    • system:表示表中只有一條記錄;
    • const:表示表中有多條記錄,但只從表中查詢一條記錄;
    • eq _ref:類似 ref,表示多表連線時,後面的表使用了 UNIQUE 或者 PRIMARY KEY;
    • ref:表示多表查詢時,後面的表使用了普通索引;
    • range:表示查詢語句中給出了查詢範圍,常見於 <、<=、>、>=、between 等操作符;
    • index:表示對錶中的索引進行了完整的掃描,MySQL 遍歷整個索引來查詢匹配的行;
    • ALL:表示對錶進行了完整的掃描,MySQL 遍歷全表來找到匹配的行。
  6. possible_keys:表示查詢中可以使用的索引;
  7. key:表示實際查詢中使用到的索引;
  8. key_len:表示索引欄位的長度;
  9. ref:表示使用哪個列或常數與索引一起來查詢記錄;
  10. rows:表示查詢的行數;
  11. filtered:MySQL 5.7 版本之前使用 EXPLAIN EXTENDED 時會出現這個欄位,MySQL 5.7 版本之後包括 5.7 版本預設就有這個欄位。這個欄位表示儲存引擎返回的資料在 server 層過濾後,剩下多少滿足查詢記錄數量的比例。注意是百分比,不是具體記錄數。
  12. Extra:表示查詢過程的附件資訊。

DESCRIBE

DESCRIBE 語句的使用方法與 EXPLAIN 語句一樣,DESCRIBE 語句的語法形式如下:

DESCRIBE SELECT語句;

DESCRIBE 可以縮寫成 DESC。

索引對查詢速度的影響

索引是資料庫優化中最常用也是最重要的手段之一,通過索引可以幫助使用者解決大多數的 SQL 效能問題。

多數情況下,查詢速度很慢時,加上索引便能解決問題。但也並非總是如此,因為優化不是件簡單的事情。但是如果你不使用索引,在許多情況下,嘗試通過其它途徑來提高效能都純粹是在浪費時間。應該首先使用索引來最大程度的改善效能,然後再看看是否還有其它有用的技術。

索引提供了高效訪問資料的方法,能夠快速的定位表中的某條記錄,加快資料庫查詢的速度,從而提高資料庫的效能。

如果查詢時不使用索引,那麼查詢語句將查詢表中的所有欄位。這樣查詢的速度會很慢。使用索引進行查詢,查詢語句不必讀完表中的所有記錄,而只查詢索引欄位。這樣可以減少查詢的記錄數,達到提高查詢速度的目的。

下面通過對比使用索引和不使用索引來分析索引對查詢速度的影響。

為了便於讀者更好的理解,分析之前,我們先查詢一下 tb_students_info 資料表中的記錄,SQL 語句和執行結果如下:

mysql> SELECT * FROM tb_students_info;
+----+------+
| id | name |
+----+------+
|  1 | 張三 |
|  2 | 李四 |
|  3 | 王五 |
|  4 | 趙六 |
|  5 | 周七 |
|  6 | 吳八 |
|  7 | 朱九 |
|  8 | 蘇十 |
+----+------+
8 rows in set (0.02 sec)

使用 EXPLAIN 分析未使用索引時的查詢情況,SQL 語句和執行結果如下:

mysql> EXPLAIN SELECT * FROM tb_students_info WHERE name='張三' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_students_info
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 8
     filtered: 12.50
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

由結果可以看到,rows 列的值是 8,說明查詢語句掃描了表中的 8 條記錄。

注意:沒有索引的表就相當於一組無序的行,如果我們想找到某條記錄就必須檢查表的每一行,看看它是否與那個期望值相匹配。這是一個全表掃描操作,其效率很低,如果表很大,而且僅有少數幾條記錄與搜尋條件相匹配,那麼整個掃描過程的效率將會超級低。

在 tb_students_info 表的 name 欄位新增索引,SQL 語句和執行結果如下:

mysql> CREATE INDEX index_name ON tb_students_info(name);
Query OK, 8 rows affected (0.14 sec)

使用 EXPLAIN 再次執行上面的查詢語句,SQL 語句和執行結果如下:

mysql> EXPLAIN SELECT * FROM tb_students_info WHERE name='張三' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_students_info
   partitions: NULL
         type: ref
possible_keys: index_name
          key: index_name
      key_len: 63
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

結果顯示,rows 列的值為 1,表示這個查詢語句只掃描了表中的 1 條記錄。建立索引後訪問的行由 8 行減少到 1 行,其查詢速度自然比掃描 8 條記錄快。而且 possible_keys 和 key 的值都是 index_name,這說明查詢時使用了 index_name 索引。所以,在查詢操作中,使用索引不僅能自動優化查詢效率,還會降低伺服器的開銷。

注意:由於 tb_students_info 表中記錄較少,所以在這沒有分析執行時間。表中記錄多時,執行時間的差異也會體現出索引對查詢速度的影響。

MySQL優化資料庫結構

一個好的資料庫設計方案會對資料庫的效能起到事半功倍的效果。合理的資料庫結構不僅可以使資料庫佔用更小的磁碟空間,而且能夠使查詢速度更快。

資料庫結構是否合理,需要考慮是否存在冗餘、對錶的查詢和更新的速度、表中欄位的資料型別是否合理等多方面的內容

分解表

有些表在設計時設定了很多的欄位,而有些欄位的使用頻率非常低。這樣當這個表的資料量很大時,查詢資料的速度就會很慢。我們可以將這些使用頻率較低的欄位分離出來形成新表。

例子:在 student 資料表中有很多欄位,其中 comment 欄位用來儲存學生的備註資訊。

備註資訊的內容特別多,但是該欄位很少使用。這時就可以分解出另外一個表。分解出的表為 student_comment,表中儲存 2 個欄位

  • id :id 為學生的學號
  • comment:comment 為學生備註資訊

student_comment 的表結構如下:

mysql> DESC `student_comment`;
+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| id      | int(11) | NO   | PRI | NULL    |       |
| comment | text    | YES  |     | NULL    |       |
+---------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

如果需要查詢某個學生的備註資訊,可以使用學號(id)來查詢。如果需要將學生的學籍資訊與備註資訊同時顯示,可以使用表連線查詢 student 表和 student_comment 表,查詢語句如下:

SELECT * FROM student, student_comment WHERE student.id=student_comment.id;

通過以上方法,可以有效的提高 student 表的查詢效率。

增加中間表

表連線會降低資料庫的查詢速度,所以對於經常使用表連線查詢的表,我們可以建立中間表來提高查詢速度。

首先分析經常需要同時查詢哪幾個表中的哪些欄位,然後將這些欄位建立一箇中間表,並將原來那幾個表的資料插入到中間表中,之後就可以使用中間表來進行查詢和統計了。

例子:下面有兩個資料表,分別是 student(學生)表和 score(分數)表。這兩個表的結構如下:

mysql> DESC student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int(11)     | NO   | PRI | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| sex     | varchar(4)  | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| address | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> DESC score;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| stu_id | int(11)     | NO   | MUL | NULL    |       |
| c_name | varchar(20) | YES  |     | NULL    |       |
| grade  | int(11)     | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

實際應用中,經常需要查詢學生的學號、姓名和成績。對於這種情況,我們可以建立一個 temp_score 表。temp_score 表中儲存 3 個欄位,分別是 id、name 和 grade。

建立 temp_score 的 SQL 語句如下:

mysql> CREATE TABLE temp_score(
-> id INT NOT NULL,
-> name VARCHAR(20) NOT NULL,
-> grade FLOAT
-> );
Query OK, 0 rows affected (0.00 sec)

然後從 student 表和 score 表中將記錄匯入到 temp_score 表中。INSERT 語句如下:

INSERT INTO temp_score SELECT student.id, student.name, score.grade
FROM student, score WHERE student.id=score.stu_id;

將這些資料插入到 temp_score 表中以後,可以直接從 temp_score 表中查詢學生的學號、姓名和成績。這樣就省去了每次查詢時進行表連線,提高了資料庫的查詢速度。

增加冗餘欄位

一般情況下,設計資料庫時應儘量讓表符合三大正規化。但是,有時為了提高查詢速度,可以有意識地在表中增加冗餘欄位。

表的規範化程度越高,表與表之間的關係就越多,查詢時也就經常需要在多個表之間進行連線查詢,而連線操作會降低查詢速度。

  • 例如,學生的資訊儲存在 student 表中,院系資訊儲存在 department 表中。通過 student 表中的 dept_id 欄位與 department 表建立關聯關係。

如果要查詢一個學生所在系的名稱,就必須從 student 表中查詢學生所在院系的編號(dept_id),然後根據這個編號去 department 查詢系的名稱。這個連線查詢會浪費很多的時間。因此可以在 student 表中增加一個冗餘欄位 deptname,用來儲存學生所在院系的名稱。這樣就不用每次都進行連線操作了。

分解表、增加中間表和增加冗餘欄位都浪費了一定的磁碟空間。從資料庫效能的角度來看,增加少量的冗餘來提高資料庫的查詢速度是可以接受的。是否通過增加冗餘來提高資料庫效能,這要根據 MySQL 伺服器的具體要求來定。如果磁碟空間很大,可以考慮犧牲一點磁碟空間。

MySQL優化插入資料速度

在 MySQL 中,向資料表插入資料時,索引、唯一性檢查、資料大小是影響插入速度的主要因素。

根據不同情況,可以分別進行優化。

MyISAM 引擎表優化方法

禁用索引

對非空表插入資料時,MySQL 會根據表的索引對插入的記錄進行排序。插入大量資料時,這些排序會降低插入資料的速度。為了解決這種情況,可以在插入資料之前先禁用索引,等到資料都插入完畢後在開啟索引。

禁用索引的語句為:

ALTER TABLE table_name DISABLE KEYS;

重新開啟索引的語句為:

ALTER TABLE table_name ENABLE KEYS;

對於新建立的表,可以先不建立索引,等到資料都匯入以後再建立索引,這樣可以提高匯入資料的速度。

禁用唯一性檢查

插入資料時,MySQL 會對插入的資料進行唯一性檢查。這種唯一性檢驗會降低插入資料的速度。為了降低這種情況對查詢速度的影響,可以在插入資料前禁用唯一性檢查,等到插入資料完畢後在開啟。

禁用唯一性檢查的語句為:

SET UNIQUE_CHECKS=0;

開啟唯一性檢查的語句為:

SET UNIQUE_CHECKS=1;

使用批量插入

在 MySQL 中,插入多條資料有 2 種方式。第一種是使用一個 INSERT 語句插入多條資料。INSERT 語句的情形如下:

INSERT INTO items(name,city,price,number,picture) VALUES ('耐克運動鞋','廣州',500,1000,'001.jpg'),('耐克運動鞋2','廣州2',500,1000,'002.jpg');

第二種是一個 INSERT 語句只插入一條資料,執行多個 INSERT 語句來插入多條資料。INSERT 語句的情形如下:

INSERT INTO items(name,city,price,number,picture) VALUES('耐克運動鞋','廣州',500,1000,'001.jpg');
INSERT INTO items(name,city,price,number,picture) VALUES('耐克運動鞋2','廣州',500,1000,'002.jpg');

一次性插入多條資料和多次插入資料所耗費的時間是不一樣的。第一種方式減少了與資料庫之間的連線等操作,其速度比第二種方式要快一些。所以插入大量資料時,建議使用第一種方法。

注意:如果能用 LOAD DATA INFILE 語句,就儘量用 LOAD DATA INFILE 語句。因為 LOAD DATA INFILE 語句匯入資料的速度比 INSERT 語句的速度快。

InnoDB 引擎表優化方法

禁用索引&禁用唯一性檢查

同 MyISAM 引擎相同,插入資料之前先禁用索引,等到資料都插入完畢後在開啟索引。

禁用外來鍵檢查

使用外來鍵時,在子表中插入一條資料,首先會檢查主表中是否有相應的主鍵值,然後鎖定主表的記錄,在插入值。相比較,使用外來鍵多了2步操作,速度會慢一些。所以我們可以在插入資料之前禁止對外來鍵的檢查,資料插入完成之後再恢復對外來鍵的檢查。不多對於資料完整性要求較高的系統不建議使用。

禁用外來鍵檢查語句為:

SET FOREIGN_KEY_CHECKS=0; 

恢復對外來鍵的檢查語句為:

SET FOREIGN_KEY_CHECKS=1;

禁止自動提交

MySQL 的事務自動提交模式預設是開啟的,其對 MySQL 的效能也有一定得影響。也就是說如果你插入了 1000 條資料,MySQL 就會提交 1000 次,這大大影響了插入資料的速度。而如果我們把自動提交關掉,通過程式來控制,只要一次提交就可以了。

所以插入資料之前可以先禁止事務的自動提交,待資料匯入完成之後,再恢復自動提交操作。

禁止自動提交語句為:

SET AUTOCOMMIT=0; 

恢復自動提交語句為:

SET AUTOCOMMIT=1;

優化MySQL伺服器

MySQL 中,可以通過兩個方面來優化伺服器,即硬體和配置引數的優化。通過這些優化方式,可以提高 MySQL 的執行速度。

優化伺服器硬體

伺服器的硬體直接決定著 MySQL 資料庫的效能。例如,增加記憶體和提高硬碟的讀寫速度,可以提高 MySQL 資料庫的查詢、更新的速度。

優化伺服器硬體的方法主要有以下幾種:

  • 配置較大的記憶體
  • 配置高速磁碟系統,以減少讀盤的等待時間,提高響應速度
  • 合理分佈磁碟 I/O,把磁碟 I/O 分散在多個裝置上,以減少資源競爭,提高並行操作能力
  • 配置多處理器,MySQL 是多執行緒的資料庫,多處理器可同時執行多個執行緒

隨著硬體技術的成熟,硬體的價格也隨之降低。現在普通的個人電腦都已經配置了 8GB 記憶體,甚至一些個人電腦配置 16GB/32GB/64GB 記憶體。因為記憶體的讀寫速度比硬碟的讀寫速度快。可以在記憶體中為 MySQL 設定更多的緩衝區,這樣可以提高 MySQL 的訪問的速度。如果將查詢頻率很高的記錄儲存在記憶體中,那麼查詢速度就會很快。

如果條件允許,可以將記憶體提高。並且選擇 my-innodb-heavy-4G.ini 作為 MySQL 資料庫的配置檔案。但是,這個配置檔案主要支援 InnoDB 儲存引擎的表。如果使用 8GB 記憶體,可以選擇 my-huge.ini 作為配置檔案。MySQL 所在的計算機最好是專用資料庫伺服器,這樣資料庫就可以完全利用該機器的資源。

伺服器型別分為 Developer Machine、Server Machine 和 Dedicate MySQL Server Machine。其中 Developer Machine 用來做軟體開發的時候使用,資料庫佔用的資源比較少。後面兩者佔用的資源比較多,尤其是 Dedicate MySQL Server Machine,其幾乎要佔用所有的資源。

還可以使用多塊磁碟來儲存資料。這樣可以從多個磁碟上並行讀取資料,提高資料庫讀取資料的速度。通過映象機制可以將不同計算機上的 MySQL 伺服器進行同步,這些 MySQL 伺服器中的資料都是一樣的。

通過不同的 MySQL 伺服器來提供資料庫服務,這樣可以降低單個 MySQL 伺服器的壓力,從而提高 MySQL 的效能。

優化MySQL引數

和大多數資料庫一樣,MySQL 提供了很多引數來進行伺服器的優化設定。資料庫伺服器第一次啟動時,很多引數都是預設設定的,這在實際應用中並不能完全滿足需求,為此資料庫管理員要進行必要的設定。

檢視效能引數的方法

MySQL 伺服器啟動之後,可以使用 SHOW VARIABLES 命令檢視系統引數,也可稱為靜態引數。這些引數是系統預設或者 DBA 調整優化後的引數,可以通過 SET 命令或在配置檔案中修改。

使用 SHOW STATUS 命令查詢伺服器執行的實時狀態資訊,也就是動態引數。便於 DBA 檢視當前 MySQL 執行的狀態,做出相應優化,不能手動修改。

例子:下面為使用 SHOW VARIABLES 和 SHOW STATUS 命令的例項。

mysql> SHOW VARIABLES LIKE 'key_buffer_size';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| key_buffer_size | 33554432 |
+-----------------+----------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW STATUS LIKE 'key_read_requests';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Key_read_requests | 149   |
+-------------------+-------+
1 row in set (0.01 sec)

設定優化效能引數

在 MySQL 中,有些引數直接影響到系統的效能。我們可以通過優化 MySQL 的引數提高資源利用率,從而達到提高 MySQL 伺服器效能的目的。

以下配置引數都在 my.cnf 或者 my.ini 檔案的 [mysqld] 組中。

  1. key_buffer_size(針對MyISAM儲存引擎):表示索引快取的大小,這個引數是對 MyISAM 表效能影響最大的一個引數。值越大,索引進行查詢的速度越快。
    • 通過檢查狀態值 key_read_requests 和 key_reads,可以知道 key_buffer_size 的值是否合理。正常情況下,key_reads / key_read_requests 的比例值需小於 0.01。
  2. table_cache(針對MyISAM儲存引擎):表示資料庫使用者同時開啟的表的個數。值越大,能夠同時開啟的表的個數越多。需要注意的是,這個值不是越大越好,因為同時開啟的表太多會影響作業系統的效能。
    • 在設定該引數的時候,可以通過 open_tables 和 opened_tables 變數的值來確定該引數的值。open_tables 參數列示當前開啟的表快取數,opened_tables 參數列示曾經開啟的表快取數。
    • 如果 open_tables 的值已經接近 table_cache 的值,且 opened_tables 還在不斷變大,則說明 MySQL 正在將快取的表釋放以容納新的表,此時可能需要加大table_cache 的值。對於大多數情況,比較適合的值如下:
      • open_tables / opened_tables >= 0.85
      • open_tables / table_cache <= 0.95
    • 執行 FLUSH TABLE 操作後,系統會關閉一些當前沒有使用的表快取,因此 FLUSH TABLE 後,open_tables 引數的值會變小,opened_tables 引數的值不會變。
  3. query_cache_size:表示查詢快取區的大小。使用查詢快取區可以提高查詢的速度。記憶體中會為 MySQL 保留部分的快取區,這些快取區可以提高 MySQL 的處理速度。可以從以下幾個方面考慮如何設定該引數的大小:
    • 查詢快取對 DDL 和 DML 語句的效能的影響
    • 查詢快取的內部維護成本
    • 查詢快取的命中率以及記憶體使用率等因素
  4. query_cache_type:表示查詢緩衝區的開啟狀態,用於控制查詢結果是否放到查詢快取中。這種方式只適用於修改操作少且經常執行相同的查詢操作的情況,其預設值為 0。
    • 值為 0 表示關閉;
    • 值為 1 表示開啟;
    • 值為 2 表示按要求使用查詢快取區,只有 SELECT 語句中使用了 SQL_CACHE 關鍵字,查詢快取區才會使用。例如,SELECT SQL_CACHE * FROM student。
  5. max_connections:表示資料庫的最大連線數,預設值為 100。引數最大值不能超過 16384,即使超過也以 16384 為準。該引數設定過小的最明顯特徵是出現“Too many connections”錯誤。當然連線數也不是越大越好,因為這些連線會浪費記憶體的資源。
  6. sort_buffer_size:表示排序快取區的大小。值越大,排序的速度越快。
  7. read_buffer_size:表示為每個執行緒保留的緩衝區的大小。當執行緒需要從表中連續讀取記錄時需要用到這個緩衝區。
  8. read_rnd_buffer_size:表示為每個執行緒保留的緩衝區的大小,與 read_buffer_size 相似。但主要用於儲存按特定順序讀取出來的記錄。
  9. innodb_buffer_pool_size:表示 InnoDB 型別的表和索引的最大快取。值越大,查詢的速度越快。但是這個值太大了也會影響作業系統的效能。
  10. 調優參考計算方法:
    • val = Innodb_buffer_pool_pages_data / Innodb_buffer_pool_pages_total * 100%
    • val > 95% 則考慮增大 innodb_buffer_pool_size, 建議使用實體記憶體的 75%
    • val < 95% 則考慮減小 innodb_buffer_pool_size, 建議設定為:Innodb_buffer_pool_pages_data * Innodb_page_size * 1.05 / (102410241024)
  11. innodb_log_file_size:該引數的作用是設定日誌組中每個日誌檔案的大小。該引數在高寫入負載尤其是大資料集的情況下很重要,這個值越大則效能相對較高。最好不要超過 innodb_log_files_in_group * innodb_log_file_size 的 0.75。
  12. innodb_log_files_in_group:該引數用於指定資料庫中有幾個日誌組,預設為2個,因為有可能出現跨日誌的大事務,一般來講,建議使用 3~4 個日誌組。
  13. innodb_log_buffer_size:該引數的作用是設定日誌快取的大小,一旦提交事務,則將該快取池中的內容寫到磁碟的日誌檔案上。該引數的設定在中等強度寫入負載以及較短事務情況下,一般都可以滿足伺服器的效能要求。如果伺服器負載較大,可以考慮加大該引數的值。一般快取池中的記憶體每秒鐘寫到磁碟一次,所以設定較大會浪費記憶體空間,一般設定為 8MB~16MB 就足夠了。可以參考 Innodb_os_log_written 的值,如果該值增加過快,可以適當的增加該引數的值。
  14. innodb_flush_log_at_trx_commit:表示何時將緩衝區的資料寫入日誌檔案,並且將日誌檔案寫入磁碟中。該引數有 3 個值,分別為 0、1 和 2。
    • 值為 0 時,表示每隔 1 秒將資料寫入日誌檔案並將日誌檔案寫入磁碟;
    • 值為 1 時,表示每次提交事務時將資料寫入日誌檔案並將日誌檔案寫入磁碟;
    • 值為 2 時,表示每次提交事務時將資料寫入日誌檔案,每隔 1 秒將日誌檔案寫入磁碟。

該引數的預設值為 1,是最安全最合理的值。為了保證事務的永續性和一致性,建議將該引數設定為 1。

引數設定的值要根據自己的實際情況來設定,並不是值越大越好,可能設定的數值太大體現不出優化效果,反而造成系統空間被佔用,導致作業系統變慢。合理的配置引數可以提高 MySQL 伺服器的效能。需要注意的是,配置完引數以後,需要重新啟動 MySQL 服務配置才會生效。

相關文章