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
:每秒查詢數,一臺數據庫每秒能夠處理的查詢次數
TPS
,Transactions 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_commit
和Com_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
、mysqlhotcopy
、xtrabackup
等,mysqldump
比較適用于小的數據庫,因為是邏輯備份,所以備份和恢復耗時都比較長。mysqlhotcopy和xtrabackup
是物理備份,備份和恢復速度快,不影響數據庫服務情況下進行熱拷貝,建議使用xtrabackup,支持增量備份。
1.4.1 myqldump示例
使用myqldump
時,注意myqldump
不是sql語句,mysqldump
是mysql
用于轉存儲數據庫的實用程序
不能在MySQL可視化工具或者DOS里的mysql下直接執行。
- 導出整個數據庫
導出文件默認是存在mysql\bin
目錄下
mysqldump -u 用戶名 -p 數據庫名 > 導出的文件名
mysqldump -u user_name -p123456 database_name > outfile_name.sql
- 導出一個表
mysqldump -u 用戶名 -p 數據庫名 表名> 導出的文件名
mysqldump -u user_name -p database_name table_name > outfile_name.sql
- 導出一個數據庫結構
mysqldump -u user_name -p -d -add-drop-table database_name > outfile_name.sql
-d 沒有數據 –add-drop-table 在每個create語句之前增加一個drop table
- 帶語言參數導出
mysqldump -uroot -p –default-character-set=latin1 –set-charset=gbk –skip-optdatabase_name > outfile_name.sql
1.5 數據庫修復
有時候MySQL
服務器突然斷電、異常關閉,會導致表損壞,無法讀取表數據。這時就可以用到MySQL
自帶的兩個工具進行修復,myisamchk
和mysqlcheck
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修復
mysqlcheck
: myisam和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)
恢復方法介紹(過程):
- 在新的正常工作的
MYSQL
環境下建立一個數據庫,比如aa
- 在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)
- 把系統崩潰后留下的
test_innodb.frm
文件拷貝到此處正常數據庫的數據目錄aa下,覆蓋掉下邊同名的.frm文件
- 重新啟動MYSQL服務。
- 測試下是否恢復成功,進入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)
恢復過程如下:
- 直接將
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命令報錯。
- 在與
test_myisam.frm
同一目錄建立以下2個文件,文件內容可以為空:test_myisam.MYD
表數據文件和test_myisam.MYI
索引文件 - 在
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%';
值為OFF
,需開啟,值為ON
,表示已開啟
如果沒有開啟 binlog
,也沒有預先生成回滾SQL
,那可能真的無法快速回滾了。對存放重要業務數據的 MySQL
,強烈建議開啟 binlog
1.6.2 查找日志文件
1.6.2.1 路徑下查找
進入binlog
文件目錄,找出日志文件
1.6.2.2 命令下查找
查看下當前正在寫入的 binlog
文件:
show master status;
也可以查看下當前有多少個
binlog
日志文件了:
show binary logs;
1.6.3 通過mysqlbinlog查看DML記錄
1.6.3.1 在mysql服務器內
切換到mysqlbinlog
目錄,當線上數據出現錯誤的時候首先可以詢問具體操作人記錄時間點,這個時候可以借助mysql
自帶的binlog
解析工具mysqlbinlog
,具體位置在mysql
安裝目錄 **/mysql/bin/
下
通過 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
1.6.3.2 用命令查看
在 SQL 控制臺查看下 binlog
信息:
show binlog events in 'binlog.000002';
這樣還不能看出剛才修改前的內容,下面就要使用 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
采用磁盤臨時文件排序,最終影響查詢性能