MySQL之數據庫維護

1 數據庫維護

數據庫維護是運維工程師或者DBA主要工作,包括性能監控、性能分析、性能調優、數據庫備份和恢復等。

1.1 數據庫文件

MySQL的每個數據庫都對應存放在一個與數據庫同名的文件夾中,MySQL數據庫文件包括MySQL所建數據庫文件和MySQL所用存儲引擎創建的數據庫文件。

1.1.1 MySQL創建并管理的數據庫文件

.frm文件:存儲數據表的框架結構,文件名與表名相同,每個表對應一個同名frm文件,與操作系統和存儲引擎無關,即不管MySQL運行在何種操作系統上,使用何種存儲引擎,都有這個文件。
除了必有的.frm文件,根據MySQL所使用的存儲引擎的不同(MySQL常用的兩個存儲引擎是MyISAM和InnoDB),存儲引擎會創建各自不同的數據庫文件

MyISAM數據庫表文件:

  • .MYD文件:即MY Data,表數據文件
  • .MYI文件:即MY Index,索引文件
  • .log文件:日志文件

InnoDB采用表空間(tablespace)來管理數據,存儲表數據和索引,InnoDB數據庫文件(即InnoDB文件集,ib-file set):

  • ibdata1、ibdata2等:系統表空間文件,存儲InnoDB系統信息和用戶數據庫表數據和索引,所有表共用
  • .ibd文件:單表表空間文件,每個表使用一個表空間文件(file per table),存放用戶數據庫表數據和索引
  • 日志文件: ib_logfile1、ib_logfile2

1.1.2 MySQL數據庫存放位置

MySQL如果使用MyISAM存儲引擎,數據庫文件類型就包括.frm、.MYD、.MYI,默認存放位置是C:\Documentsand Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data

MySQL如果使用InnoDB存儲引擎,數據庫文件類型就包括.frm、ibdata1、.ibd.frm.ibd文件默認存放位置是MySQL安裝目錄下的data文件夾

1.2 性能狀態關鍵指標QPS和TPS

QPS,Queries Per Second:每秒查詢數,一臺數據庫每秒能夠處理的查詢次數
TPSTransactions Per Second:每秒處理事務數
通過show status查看運行狀態,會有300多條狀態信息記錄,其中有幾個值幫可以我們計算出QPS和TPS,如下:

  • Uptime:服務器已經運行的實際,單位秒
  • Questions:已經發送給數據庫查詢數
  • Com_select:查詢次數,實際操作數據庫的
  • Com_insert:插入次數
  • Com_delete:刪除次數
  • Com_update:更新次數
  • Com_commit:事務次數
  • Com_rollback:回滾次數

那么,計算方法來了,基于Questions計算出QPS

mysql> show global status like 'Questions';
mysql> show global status like 'Uptime';
QPS = Questions / Uptime

基于Com_commitCom_rollback計算出TPS:

mysql> show global status like 'Com_commit';
mysql> show global status like 'Com_rollback';
mysql> show global status like 'Uptime';
TPS = (Com_commit + Com_rollback) / Uptime

另一計算方式:基于Com_select、Com_insert、Com_delete、Com_update計算出QPS

mysql> show global status where Variable_name in('com_select','com_insert','com_delete','com_update');

等待1秒再執行,獲取間隔差值,第二次每個變量值減去第一次對應的變量值,就是QPS

TPS計算方法:

mysql> show global status where Variable_name in('com_insert','com_delete','com_update');

計算TPS,就不算查詢操作了,計算出插入、刪除、更新四個值即可。
經網友對這兩個計算方式的測試得出,當數據庫中myisam表比較多時,使用Questions計算比較準確。當數據庫中innodb表比較多時,則以Com_*計算比較準確。

1.3 開啟慢查詢日志

MySQL開啟慢查詢日志,分析出哪條SQL語句比較慢,使用set設置變量,重啟服務失效,可以在my.cnf添加參數永久生效。

mysql> set global slow-query-log=on  #開啟慢查詢功能
mysql> set global slow_query_log_file='/var/log/mysql/mysql-slow.log';  #指定慢查詢日志文件位置
mysql> set global log_queries_not_using_indexes=on;   #記錄沒有使用索引的查詢
mysql> set global long_query_time=1;   #只記錄處理時間1s以上的慢查詢

分析慢查詢日志,可以使用MySQL自帶的mysqldumpslow工具,分析的日志較為簡單。

mysqldumpslow -t 3 /var/log/mysql/mysql-slow.log    
#查看最慢的前三個查詢

也可以使用percona公司的pt-query-digest工具,日志分析功能全面,可分析slow log、binlog、general log。

分析慢查詢日志:pt-query-digest /var/log/mysql/mysql-slow.log
分析binlog日志:mysqlbinlog mysql-bin.000001 >mysql-bin.000001.sql
pt-query-digest –type=binlog mysql-bin.000001.sql
分析普通日志:pt-query-digest –type=genlog localhost.log

1.4 數據庫備份

備份數據庫是最基本的工作,也是最重要的,否則后果很嚴重,但由于數據庫比較大,上百G,往往備份都很耗費時間,所以就該選擇一個效率高的備份策略,對于數據量大的數據庫,一般都采用增量備份。常用的備份工具有mysqldump、mysqlhotcopyxtrabackup等,mysqldump比較適用于小的數據庫,因為是邏輯備份,所以備份和恢復耗時都比較長。mysqlhotcopy和xtrabackup是物理備份,備份和恢復速度快,不影響數據庫服務情況下進行熱拷貝,建議使用xtrabackup,支持增量備份。

1.4.1 myqldump示例

使用myqldump時,注意myqldump不是sql語句,mysqldumpmysql用于轉存儲數據庫的實用程序

不能在MySQL可視化工具或者DOS里的mysql下直接執行。

  1. 導出整個數據庫
    導出文件默認是存在mysql\bin目錄下
mysqldump -u 用戶名 -p 數據庫名 > 導出的文件名
mysqldump -u user_name -p123456 database_name > outfile_name.sql
  1. 導出一個表
mysqldump -u 用戶名 -p 數據庫名 表名> 導出的文件名
mysqldump -u user_name -p database_name table_name > outfile_name.sql
  1. 導出一個數據庫結構
mysqldump -u user_name -p -d -add-drop-table database_name > outfile_name.sql
-d 沒有數據 –add-drop-table 在每個create語句之前增加一個drop table
  1. 帶語言參數導出
mysqldump -uroot -p –default-character-set=latin1 –set-charset=gbk –skip-optdatabase_name > outfile_name.sql

1.5 數據庫修復

有時候MySQL服務器突然斷電、異常關閉,會導致表損壞,無法讀取表數據。這時就可以用到MySQL自帶的兩個工具進行修復,myisamchkmysqlcheck

1.5.1 myisamchk修復

myisamchk: 只能修復myisam表,需要停止數據庫
常用參數:

  • -f –force 強制修復,覆蓋老的臨時文件,一般不使用
  • -r –recover 恢復模式
  • -q –quik 快速恢復
  • -a –analyze 分析表
  • -o –safe-recover 老的恢復模式,如果-r無法修復,可以使用此參數試試
  • -F –fast 只檢查沒有正常關閉的表

快速修復weibo數據庫:

cd /var/lib/mysql/weibo
myisamchk -r -q *.MYI

1.5.2 mysqlcheck修復

mysqlcheckmyisam和innodb表都可以用,不需要停止數據庫,如修復單個表,可在數據庫后面添加表名,以空格分割
常用參數:

  • -a –all-databases 檢查所有的庫
  • -r –repair 修復表
  • -c –check 檢查表,默認選項
  • -a –analyze 分析表
  • -o –optimize 優化表
  • -q –quik 最快檢查或修復表
  • -F –fast 只檢查沒有正常關閉的表

快速修復weibo數據庫:

mysqlcheck -r -q -uroot -p123 weibo

1.5.3 .frm文件修復

MYSQL中建立任何一張數據表,在其數據目錄對應的數據庫目錄下都有對應表的.frm文件.frm文件是用來保存每個數據表的元數據(meta)信息,包括表結構的定義等,.frm文件跟數據庫存儲引擎無關,也就是任何存儲引擎的數據表都必須有.frm文件,命名方式為數據表名.frm,如user.frm。 .frm文件可以用來在數據庫崩潰時恢復表結構。

1.5.3.1 InnoDB表結構的恢復

假定:MYSQL數據庫已經崩潰,目前只有對應表的.frm文件,大家都知道,.frm文件無法通過文本編輯器查看,因為如果不恢復,基本上來說對我們沒什么用。這里我們為了測試,假定該文件為test_innodb.frm

該表創建腳本如下(建表后就把該表所在數據庫服務器給強行關閉,模擬崩潰場景)

mysql> create table test_innodb
    -> (A int(11) default NULL,
    -> B varchar(30) default NULL,
    -> C date default NULL) engine=innodb;
Query OK, 0 rows affected (0.05 sec)

恢復方法介紹(過程):

  1. 在新的正常工作的MYSQL環境下建立一個數據庫,比如aa
  2. 在aa數據庫下建立同名的數據表test_innodb,表結構隨意,這里只有一個id字段,操作過程片段如下:
mysql> create table test_innodb (id bigint not null)engine=InnoDB;
Query OK, 0 rows affected (0.09 sec)

mysql> show tables;
+--------------+
| Tables_in_aa |
+--------------+
| test_innodb |
+--------------+
2 rows in set (0.00 sec)

mysql> desc test_innodb;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| id    | bigint(20) | NO   |     | NULL    |       |
+-------+------------+------+-----+---------+-------+
1 row in set (0.00 sec)
  1. 把系統崩潰后留下的test_innodb.frm文件拷貝到此處正常數據庫的數據目錄aa下,覆蓋掉下邊同名的.frm文件
  2. 重新啟動MYSQL服務。
  3. 測試下是否恢復成功,進入aa數據庫,用desc命令測試下:
mysql> desc test_innodb;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| A     | int(11)     | YES  |     | NULL    |       |
| B     | varchar(30) | YES  |     | NULL    |       |
| C     | date        | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

OK,發現表結構已經恢復過來了。

1.5.3.2 MyISAM表結構的恢復

MyISAM類型的表恢復相對比較簡單。
同樣先假定需要恢復的表的FRM文件為test_myisam.frm,表結構為

mysql> create table test_myisam
    -> (A int(11) default NULL,
    -> B varchar(30) default NULL,
    -> C date default NULL) engine=myisam;
Query OK, 0 rows affected (0.05 sec)

恢復過程如下:

  1. 直接將test_myisam.frm拷貝到正常數據庫對應的數據目錄下。這時測試
mysql> show tables;
+--------------+
| Tables_in_aa |
+--------------+
| test_innodb |
| test_myisam |
+--------------+
3 rows in set (0.00 sec)

mysql> desc test_myisam;
ERROR 1017 (HY000): Can't find file: 'test_myisam' (errno: 2)

發現只能通過show tables命令看見表名,但是表結構還是沒有恢復,desc命令報錯。

  1. 在與test_myisam.frm同一目錄建立以下2個文件,文件內容可以為空:test_myisam.MYD 表數據文件和test_myisam.MYI索引文件
  2. MYSQL命令行使用MYSQL本身的數據表恢復命令repair命令恢復表,如下:
mysql> repair table test_myisam USE_FRM;
+-----------------+--------+----------+----------+
| Table           | Op     | Msg_type | Msg_text |
+-----------------+--------+----------+----------+
| aa.test_myisam | repair | status   | OK       |
+-----------------+--------+----------+----------+
1 row in set (0.00 sec)

根據結果可以知道,恢復命令執行成功,下邊用desc命令測試下:

mysql> desc test_myisam;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| A     | int(11)     | YES  |     | NULL    |       |
| B     | varchar(30) | YES  |     | NULL    |       |
| C     | date        | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.02 sec)

果然恢復成功了。
也可以用show create table命令測試下:

mysql> show create table test_myisam;
+--------------+-----------------------------------------------------------------
----------------------------------------------------------------------+
| Table        | Create Table
                                                                      |
+--------------+-----------------------------------------------------------------
----------------------------------------------------------------------+
| test_myisam | Create TABLE `test_myisam` (
  `A` int(11) DEFAULT NULL,
  `B` varchar(30) DEFAULT NULL,
  `C` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |

在恢復MyISAM表結構時,提到MYD文件和MYI文件,這兩個文件都專屬于MyISAM存儲引擎的,前者用來保存MyISAM表的數據,后者用來存放MyISAM表的索引信息。

1.6 MySQL恢復誤刪表而丟失的數據

相信后端研發的同學在開發過程經常會遇到產品臨時修改線上數據的需求,如果手法很穩那么很慶幸可以很快完成任務,很不幸某一天突然手一抖把表里的數據修改錯誤或者誤刪了,這個時候你會發現各種問題反饋接踵而來。

1.6.1 查看是否開啟binlog

保證 mysql 已經開啟 binlog,查看命令:

查看binklog是否開啟
show variables like '%log_bin%';

查看binlog存放日志文件目錄
show variables like '%datadir%';
image.png

值為OFF,需開啟,值為ON,表示已開啟
如果沒有開啟 binlog ,也沒有預先生成回滾SQL,那可能真的無法快速回滾了。對存放重要業務數據的 MySQL,強烈建議開啟 binlog

1.6.2 查找日志文件

1.6.2.1 路徑下查找

進入binlog文件目錄,找出日志文件

image.png

1.6.2.2 命令下查找

查看下當前正在寫入的 binlog 文件:

show master status;

image.png

也可以查看下當前有多少個 binlog 日志文件了:

show binary logs;
image.png

1.6.3 通過mysqlbinlog查看DML記錄

1.6.3.1 在mysql服務器內

切換到mysqlbinlog目錄,當線上數據出現錯誤的時候首先可以詢問具體操作人記錄時間點,這個時候可以借助mysql自帶的binlog解析工具mysqlbinlog,具體位置在mysql 安裝目錄 **/mysql/bin/

image.png

通過 mysqlbinlog 工具命令查看數據庫增刪改查記錄(必須切換到 mysqlbinlog 目錄才有效)

例子1:查詢2022-11-12 09:00:00到2022-11-13 20:00:00 數據庫為 test 的操作日志,輸入如下命令將數據寫入到一個備用的txt文件中

 mysqlbinlog --no-defaults --database=test --start-datetime="2022-11-12 09:00:00" --stop-datetime="2022-11-13 20:00:00" /data/mysql/mysql-bin.000015    > template_coupon_tb_product_category.txt

例子2:查詢2022-11-12 09:00:00到2022-11-13 20:00:00 數據庫為 test 的操作日志,并輸出到屏幕上

mysqlbinlog --no-defaults --database=test --start-datetime="2022-11-12 09:00:00" --stop-datetime="2022-11-13 20:00:00" /data/mysql/mysql-bin.000015   |more

例子3:查詢2022-11-12 09:00:00到2022-11-13 20:00:00 數據庫為 test 的操作日志,并且過濾出 只包括 template_coupon_tb_product_category 表數據的操作記錄 ,輸入如下命令將數據寫入到一個備用的txt文件中

mysqlbinlog --no-defaults --database=test--start-datetime="2022-11-12 09:00:00" --stop-datetime="2022-11-13 20:00:00" /data/mysql/mysql-bin.000015   | grep template_coupon_tb_product_category   > template_coupon_tb_product_category.txt
image.png

1.6.3.2 用命令查看

在 SQL 控制臺查看下 binlog 信息:

show binlog events in 'binlog.000002';
image.png

這樣還不能看出剛才修改前的內容,下面就要使用 mysqlbinlog 工具進行分析了,首先進入到 binlog 日志的位置,我們根據時間點過濾下:

mysqlbinlog --no-defaults --base64-output=decode-rows -v --start-datetime="2022-03-13 19:00:00" --stop-datetime="2022-03-13 19:10:00" ./binlog.000002 

1.6.4 mysqlbinlog 命令

mysqlbinlog 命令的語法格式:

mysqlbinlog mysql-bin.0000xx | mysql -u用戶名 -p密碼 數據庫名

參數選項解釋:

  • start-position=875:起始pos點
  • stop-position=954:結束pos點
  • start-datetime="2022-9-25 22:01:08":起始時間點
  • stop-datetime="2022-9-25 22:09:46":結束時間點
  • database=test:指定只恢復test數據庫(一臺主機上往往有多個數據庫,只限本地log日志)
  • no-defaults:表示不使用配置文件中( my.cnf 里配的 [client] )的參數,可以避免有些 mysqlbinlog 沒有的參數導致的失敗
  • base64-output=decode-rows:解碼方式,不加的話看到的是 base64 之后的
  • v 顯示 sql 語句,也可以 vv 顯示 sql 語句和類型
  • r:可以將結果輸出到文件中
  • -u 或--user=name:連接到遠程主機的用戶名
  • -p 或--password[=name]:連接到遠程主機的密碼
  • -h 或--host=name:從遠程主機上獲取binlog日志
  • --read-from-remote-server:從某個MySQL服務器上讀取 binlog 日志

1.7 查詢表存儲空間

SELECT
    table_schema AS "數據庫",
    table_name AS "表名",
    table_rows AS "記錄數",
    TRUNCATE ( data_length / 1024 / 1024, 2 )  AS "數據容量(MB)",
    TRUNCATE ( index_length / 1024 / 1024, 2 )  AS "索引容量(MB)" 
FROM
    information_schema.TABLES 
WHERE
    table_schema = '數據庫' and TABLE_NAME = '表名'
ORDER BY
    data_length DESC,
    index_length DESC;

附錄:Varchar(50) 和 varchar(500) 區別:
全表掃描無排序情況下,兩者性能無差異,在全表有排序的情況下,兩種性能差異巨大
當使用varchar類型字段進行排序操作的時候,Mysql會根據該字段的設計的長度進行內存預估,如果設計過大的可變長度,會導致內存預估的值超出sort_buffer_size的大小,導致mysql采用磁盤臨時文件排序,最終影響查詢性能

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容