做者:陳怡
這篇文章簡單介紹一下運維中常常用到的「MySQL客戶端」的一些小技巧。這些小技巧非專業 DBA 基本不會用到,專業的 DBA 必備。但願個人分享大家也能用到。html
MySQL 客戶端的內置命令有如下這些,咱們會探索其中 6 個:mysql
List of all MySQL commands: Note that all text commands must be first on line and end with ';' ? (\?) Synonym for `help'. clear (\c) Clear the current input statement. connect (\r) Reconnect to the server. Optional arguments are db and host. delimiter (\d) Set statement delimiter. edit (\e) Edit command with $EDITOR. ego (\G) Send command to mysql server, display result vertically. exit (\q) Exit mysql. Same as quit. go (\g) Send command to mysql server. help (\h) Display this help. nopager (\n) Disable pager, print to stdout. notee (\t) Don't write into outfile. pager (\P) Set PAGER [to_pager]. Print the query results via PAGER. print (\p) Print current command. prompt (\R) Change your mysql prompt. quit (\q) Quit mysql. rehash (\#) Rebuild completion hash. source (\.) Execute an SQL script file. Takes a file name as an argument. status (\s) Get status information from the server. system (\!) Execute a system shell command. tee (\T) Set outfile [to_outfile]. Append everything into given outfile. use (\u) Use another database. Takes database name as argument. charset (\C) Switch to another charset. Might be needed for processing binlog with multi-byte charsets. warnings (\W) Show warnings after every statement. nowarning (\w) Don't show warnings after every statement. resetconnection(\x) Clean session context.
pager 的做用相似於 Linux 的管道符,能夠把輸出給另一個命令做爲輸入。linux
強大之處在於這個管道符接的命令是 Linux 命令,咱們能夠利用咱們熟悉的 Linux 命令實現各類騷操做。算法
話很少說,直接來幾個例子sql
mysql> pager less PAGER set to 'less' mysql> show engine innodb status\G 1 row in set (0.00 sec)
innodb status 的輸出很長,接 Linux 命令 less 實現翻頁,一樣地根據您我的喜愛,也能夠用 more。shell
通常來講咱們想查看目前有哪些正在跑的慢 SQL,能夠用如下命令查詢 information_schema 中的 processlist 表,這要求你熟悉元數據表。數據庫
mysql> select * from information_schema.PROCESSLIST where COMMAND='Query'; +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ | ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ | 3508 | root | localhost | information_schema | Query | 0 | executing | select * from information_schema.PROCESSLIST where COMMAND='Query' | | 3463 | root | localhost | NULL | Query | 233 | User sleep | select sleep(1000) | | 3465 | root | localhost | NULL | Query | 228 | User sleep | select sleep(2000) | | 3439 | root | localhost | NULL | Query | 235 | User sleep | select sleep(1000) | +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ 4 rows in set (0.00 sec)
但用 pager 方法的話,咱們能夠利用 Linux 的 grep 命令,更高效地獲取。服務器
mysql> pager grep Query PAGER set to 'grep Query' mysql> show processlist; | 3439 | root | localhost | NULL | Query | 23 | User sleep | select sleep(1000) | | 3463 | root | localhost | NULL | Query | 21 | User sleep | select sleep(1000) | | 3465 | root | localhost | NULL | Query | 16 | User sleep | select sleep(2000) | | 3473 | root | localhost | NULL | Query | 0 | starting | show processlist | 17 rows in set (0.00 sec)
甚至能夠直接統計數量session
mysql> pager grep Query |wc -l PAGER set to 'grep Query |wc -l' mysql> show processlist; 4 #<-- 看這裏 17 rows in set (0.00 sec)
實時發現有 4 個正在跑的查詢。app
用完 pager 記得取消,取消的方法也很簡單,有三種方法
#經常使用方法,設置pager回原默認值(stdout) mysql> pager Default pager wasn't set, using stdout. #關閉pager mysql> nopager PAGER set to stdout #退出客戶端,從新鏈接 mysql> quit Bye
tee 和 Linux 的 tee 命令是同樣的。在輸出到 stdout 同時能夠指定同時輸出到另一個文件。使用他主要能夠實現三個功能: 導數據、審計、記錄操做
mysql> tee /tmp/general_log Logging to file '/tmp/general_log' mysql> select * from general_log where event_time >'2019-11-28 00:00:00'; +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ | event_time | user_host | thread_id | server_id | command_type | argument | +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ | 2019-11-28 16:49:15.459116 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:18.604167 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:19.299166 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:20.283979 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:20.844283 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:21.289261 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:49.164062 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ 7 rows in set (0.00 sec)
[root@chenyi tmp]# cat general_log mysql> select * from general_log where event_time >'2019-11-28 00:00:00'; +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ | event_time | user_host | thread_id | server_id | command_type | argument | +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ | 2019-11-28 16:49:15.459116 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:18.604167 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:19.299166 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:20.283979 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:20.844283 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:21.289261 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | | 2019-11-28 16:49:49.164062 | root[root] @ localhost [] | 5 | 153307 | Query | select * from general_log where event_time >'2019-11-28 00:00:00' | +----------------------------+---------------------------+-----------+-----------+--------------+-------------------------------------------------------------------+ 7 rows in set (0.00 sec) mysql> \q
配置 my.cnf
[mysql] tee=/tmp/tee.log
能夠當客戶端審計用,記錄了客戶端全部屏幕輸出。(固然,這不是真正意義上的 MySQL 審計 ^ _ ^ )
"客戶端審計日誌"以下:
[root@chenyi tmp]# cat /tmp/tee.log Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 6 Server version: 5.7.27-log MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> nihao; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nihao' at line 1 mysql> \q
提醒! 使用這招要當心有人誤操做,select 了大量的數據,致使文件寫滿磁盤。
去客戶那邊排查問題,能夠考慮先開 tee,而後排查故障完畢後,看着 tee.log 去編寫故障分析郵件。
notee;
因此剛纔上面說的用 tee 審計做用不大,由於能夠關閉!
至關於在 MySQL 中使用 vi 命令來編輯 SQL 語句。這個功能比較雞肋,即便對於 vi 黨來講,效率也沒有多少提高。默認打開 edit 時,是編輯上一條 SQL 命令,退出 vi 後,輸入「;」後回車就會執行在 vi 中編輯的 SQL。
mysql> select * from information_schema.PROCESSLIST where COMMAND='Query'; +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ | ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ | 3508 | root | localhost | information_schema | Query | 0 | executing | select * from information_schema.PROCESSLIST where COMMAND='Query' | | 3463 | root | localhost | NULL | Query | 233 | User sleep | select sleep(1000) | | 3465 | root | localhost | NULL | Query | 228 | User sleep | select sleep(2000) | | 3439 | root | localhost | NULL | Query | 235 | User sleep | select sleep(1000) | +------+------+-----------+--------------------+---------+------+------------+--------------------------------------------------------------------+ 4 rows in set (0.00 sec) mysql> edit
不過有趣的是,使用 edit 能夠 隱藏客戶端操做記錄,實現「黑客操做」,下面咱們來看看:
mysql> edit -> ; PAGER set to 'grep -v 我是黑客 >>/tmp/1.log' mysql> edit -> ; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> edit -> ; 6 rows in set (0.00 sec) mysql> \q
上面是我在控制檯執行的 SQL 命令,相信你們都不知道我執行了什麼。而且下一個用戶使用個人 mysql 客戶端登陸時只能看到如下四條命令行:
edit; edit; edit; \q
這就隱藏了個人 SQL 命令行操做了。
當咱們開啓了前面咱們說的"客戶端審計日誌",咱們能夠看到如下內容:
[root@chenyi tmp]# cat /tmp/tee.log Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 Server version: 5.7.27-log MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> edit -> ; PAGER set to 'grep -v 我是黑客 >>/tmp/1.log' mysql> edit -> ; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> edit -> ; +------------------+---------------+ | user | host | +------------------+---------------+ | heike | % | | root | 10.168.65.% | | mysql.session | localhost | | mysql.sys | localhost | | root | localhost | | chenyi | localhost | +------------------+---------------+ 6 rows in set (0.00 sec) mysql> \q
這個日誌,能夠發現我有一個 pager 操做,而且最後一個 edit 後有查詢結果輸出,但具體三個 edit 裏的實際操做,咱們都無從得知。最後一個 edit 後有查詢結果輸出說明了「tee 審計方式」會忽略 pager 的過濾做用,原輸出被審計下來了,但執行的原 SQL 命令躲過了審計,被隱藏起來了。
如今,我揭曉一下:
#第一個edit pager grep -v 我是黑客 >>/tmp/1.log #第三個edit select user,host from mysql.user;
第二個 edit 咱們目前還不知道是什麼操做。固然咱們實在要排查,能夠嘗試解析 binlog 碰碰運氣,看是不是寫入操做
若是安裝了 mcafee 的審計插件,咱們在審計插件也能夠看到
{ "msg-type": "activity", "date": "1574932159871", "thread-id": "9", "query-id": "129", "user": "root", "priv_user": "root", "ip": "", "host": "localhost", "connect_attrs": { "_os": "linux-glibc2.12", "_client_name": "libmysql", "_pid": "6004", "_client_version": "5.7.27", "_platform": "x86_64", "program_name": "mysql" }, "pid": "6004", "os_user": "root", "appname": "/usr/local/mysql/bin/mysql", "status": "0", "cmd": "create_user", "query": "create user heike@'%' identified by '***'" } { "msg-type": "activity", "date": "1574932159874", "thread-id": "9", "query-id": "130", "user": "root", "priv_user": "root", "ip": "", "host": "localhost", "connect_attrs": { "_os": "linux-glibc2.12", "_client_name": "libmysql", "_pid": "6004", "_client_version": "5.7.27", "_platform": "x86_64", "program_name": "mysql" }, "pid": "6004", "os_user": "root", "appname": "/usr/local/mysql/bin/mysql", "status": "0", "cmd": "grant", "query": "grant all on *.* to heike@'%'" }
一樣的,第三個 edit,因爲是 select 操做,也會被審計插件記錄到。
{ "msg-type": "activity", "date": "1574932192709", "thread-id": "9", "query-id": "131", "user": "root", "priv_user": "root", "ip": "", "host": "localhost", "connect_attrs": { "_os": "linux-glibc2.12", "_client_name": "libmysql", "_pid": "6004", "_client_version": "5.7.27", "_platform": "x86_64", "program_name": "mysql" }, "pid": "6004", "os_user": "root", "appname": "/usr/local/mysql/bin/mysql", "rows": "35", "status": "0", "cmd": "select", "objects": [ { "db": "mysql", "name": "user", "obj_type": "TABLE" } ], "query": "select user,host from mysql.user" }
能夠看出,審計插件的審計功能能夠審計到服務器真實執行的 SQL,這是 tee 審計方式不可比擬的。但審計插件並無發現個人 pager 操做,因此並不知道我導出了數據,只有 tee 審計方式發現了我導出了數據。
identified by 'xxx'
語句的。因此,以上方式都不會泄露密碼。
惟一會泄露明文密碼的地方,是「tee審計方式」。而通過測試,結論是使用 edit 可讓明文密碼毫不泄露。
因此,edit 操做能夠隱藏密碼。
最後,我揭曉一下,我第二 edit 操做是:
create user heike@'%' identified by 'Heike@2019'; grant all on *.* to heike@'%';
不退出 mysql 客戶端狀況下執行 Linux 命令
我通常用來確認IP地址
mysql> system ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 02:00:0a:ba:41:0f brd ff:ff:ff:ff:ff:ff inet 10.186.65.15/24 brd 10.186.65.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::aff:feba:410f/64 scope link valid_lft forever preferred_lft forever
查看 MySQL 服務器狀態
mysql> status -------------- /usr/local/mysql/bin/mysql Ver 14.14 Distrib 5.7.27, for linux-glibc2.12 (x86_64) using EditLine wrapper Connection id: 11 Current database: Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '/tmp/tee.log' Using delimiter: ; Server version: 5.7.27-log MySQL Community Server (GPL) Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: utf8mb4 Db characterset: utf8mb4 Client characterset: utf8 Conn. characterset: utf8 UNIX socket: /tmp/mysql3307.sock Uptime: 1 hour 15 min 32 sec Threads: 1 Questions: 145 Slow queries: 0 Opens: 195 Flush tables: 1 Open tables: 188 Queries per second avg: 0.031 --------------
基本上去客戶那處理問題,登陸 MySQL 後第一個執行的命令行就是這個了。通常用\s
這個快捷命令。這裏能夠獲取大量想要的信息。
這裏我要特別說明兩個信息的獲取:
若是我只想知道服務器鏈接有沒有打滿,那麼我並不須要show processlist
,直接\s
,就知道了。
我這裏說的 QPS 指的是 Questions per second。
方法一
從status命令獲取
\s select sleep(1); \s
瞬時服務器真實 QPS 等於兩次\s
輸出的 Questions 差值再減 4,
由於\s
自己會形成 3 個 Questions 數,而select sleep(1);
會形成 1 個個 Questions 數。
方法二
show global status 獲取
show global status like 'Questions';select sleep(1);show global status like 'Questions';
瞬時服務器真實 QPS 等於兩次show global status like 'Questions';
輸出的差值再減 2,
由於show global status like 'Questions';
自己會形成 1 個 Questions 數,而select sleep(1);
會形成 1 個 Questions 數
方法三
最佳實踐,由於平時觀察 QPS 並非看瞬時的一個點,咱們須要持續看,因此用 mysqladmin 方法是合適的。
[root@chanyi tmp]# mysqladmin -uroot -proot -P3307 -S /tmp/mysql3307.sock -r -i 1 ext |grep -i 'question' mysqladmin: [Warning] Using a password on the command line interface can be insecure. | Questions | 162 | | Questions | 1 | | Questions | 1 | | Questions | 1 | | Questions | 1 | | Questions | 1 | | Questions | 1 | | Questions | 1 | | Questions | 1 | ^C
這個方法實際上也採用show global status
瞬時服務器真實 QPS 實際上是 0,這個數字 1 來自於每秒一次的show global status
修改 mysql 提示登陸提示符。
我通常會在兩個狀況使用它:
#主庫上 mysql> prompt master> ; PROMPT set to 'master> ' master> #從庫上 mysql> prompt slave> ; PROMPT set to 'slave> ' slave>
修改 /etc/my.cnf 配置文件
[mysql] prompt=\\U [\\d]>
修改後的效果:
root@localhost [(none)]>use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed root@localhost [test]>
如今,MySQL 客戶端登陸後能夠方便清楚是哪一個用戶登陸,切換到哪一個數據庫了。
修改 /etc/my.cnf 配置文件
[mysql] prompt=\\u@\\h:\\p \\R:\\m:\\s [\\d]>
修改後的效果:
root@127.0.0.1:3308 01:42:58 [(none)]>use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed root@127.0.0.1:3308 01:43:04 [test]>
通過這麼設置,咱們能夠經過提示符就知道咱們登陸的是哪一個數據庫實例,還能夠記錄下時間。若是再配合前面所說的"客戶端審計日誌"的話,能記錄下登陸的數據庫實例以及 SQL 的執行時間,簡直完美。
[root@chenyi tmp]# cat /tmp/tee.log Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 Server version: 5.7.27-log MySQL Community Server (GPL) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. root@127.0.0.1:3308 11:42:58 [(none)]>use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed root@127.0.0.1:3308 11:43:04 [test]> mysql> \q
以上是我一次有趣的 MySQL 客戶端命令用法的探索,但願你們喜歡。