前言
這里記錄的是這兩年學習工作過程中遇到的常用的 MySQL 語句和命令,部分是網上收集來的,出處已經不記得了,這里先謝過這些大佬。本文包括常見 SQL 語句,還有部分運維語句和命令,沒有做詳細的說明,更多是給出一個例子。就這點語句當然還不能說是全,但是后續也會陸續增加完善。記錄得有些亂,有需要的可以酌情提取。
一、用戶連接、創建、權限、刪除
1. 連接MySQL操作
mysql -h 主機地址 -u 用戶名 -P端口號 -p
使用 SSL 連接
mysql --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -h主機地址 -u用戶名 -p
2. 創建用戶
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
host
指定該用戶在哪個主機上可以登陸,如果是本地用戶可用localhost
, 如果想讓該用戶可以從任意遠程主機登陸,可以使用通配符%
.
3. 授權
GRANT [all privileges/某個權限] ON databasename.tablename TO 'username'@'host';
如果想讓該用戶可以授權,用以下命令:
GRANT all privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
4. 鎖定用戶
ALTER USER 'username'@'host' ACCOUNT LOCK;
解鎖
ALTER USER 'username'@'host' ACCOUNT UNLOCK;
常見場景:
1 創建讀寫權限的用戶
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, EXECUTE, CREATE VIEW, SHOW VIEW ON databasename.tablename TO 'username'@'host';
2 創建只讀權限用戶
GRANT SELECT,SHOW VIEW ON databasename.tablename TO 'username'@'host';
4. 設置與更改用戶密碼
方法一
SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
如果是當前登陸用戶用
SET PASSWORD = PASSWORD("newpassword");
方法二
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';
5. 撤銷用戶權限
REVOKE [ALL/某個權限] ON databasename.tablename FROM 'username'@'host';
某個用戶權限可以用命令SHOW GRANTS FOR 'username'@'host';
查看.
5. 重命名用戶
rename user 'old_name'@'host' to 'new_name'@'host';
7. 刪除用戶
DROP USER 'username'@'host';
8. 要求使用ssl登陸
# 修改已存在用戶 ALTER USER 'username'@'%' REQUIRE SSL; # 創建用戶 create user username_ssl@'%' identified by 'password' require ssl;
刷新權限表
flush privileges;
二、數據庫與表顯示、創建、刪除
1. 數據庫查看&創建&刪除
-- 查看數據庫 show databases; -- 創建庫 create database [IF NOT EXISTS] <庫名> [character set='utf8']; -- 刪除庫 drop database <庫名>;
2. 表查看、創建、刪除
-- 顯示數據表 use <庫名>; show tables; -- 創建表: create table 表名 (字段設定列表) [engine=InnoDB] [charset=utf8mb4]; -- 查看創建表的 DDL 語句 show create table <表名>; -- 顯示表結構 desc <表名>; -- 刪除表 drop table [IF EXISTS] <表名>; -- 臨時表 CREATE TEMPORARY TABLE <表名>(<字段定義>);
e.g.
CREATE TABLE USER ( id INT NOT NULL AUTO_INCREMENT, stu_id INT NOT NULL, name VARCHAR(30) NOT NULL, phone VARCHAR(20), address VARCHAR(30) NOT NULL, age INT NOT NULL, PRIMARY KEY (id), UNIQUE KEY `un_stu_id` (stu_id), KEY `idx_name` (`name`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意: 為 text 等建立索引時要指定長度 e.g. KEY
idx_text (f_text(64))
三、表復制、備份還原及清除
1. 復制表結構
含有主鍵等信息的完整表結構:
CREATE table 新表名 LIKE book;
只有表結構,沒有主鍵等信息:
create table 新表名 select * from books; 或 create table 新表名 as(select * from book); 或 create table 新表名 select * from books where1=2;
注: create table <t> select ...
會造成索引丟失
2. 將舊表中的數據灌入新表
INSERT INTO <新表> SELECT * FROM <舊表>;
3. 顯示創建表的DDL語句
show create table <表名>;
4. 清空表數據
truncate table <表名>;
5. 備份數據庫
備份單個庫
shell> mysqldump --single-transaction --master-data=2 --default-character-set=utf8 -u root -p <database_name> >database_name.sql
備份一個表
shell> mysqldump --single-transaction --master-data=2 --default-character-set=utf8 -u root -p <database_name> <table_name> > table_name.sql
備份多個庫
shell> mysqldump --single-transaction --master-data=2 --default-character-set=utf8 -u username -p --databases <dbname1> <dbname2> > Backup.sql
備份所有庫
shell> mysqldump --single-transaction --master-data=2 --default-character-set=utf8 -A -u root -p > back.sql
忽略某些庫表
--ignore-table=performance_schema.* --ignore-table=information_schema.* --ignore-table=sys.* --ignore-table=test.*
帶上壓縮
shell> mysqldump -A | gzip >> backup.sql.gz
6. 還原數據庫
shell> mysql -u root -p -f [database_name] < backup.sql
7. 從備份文件抽取數據
提取某個庫的所有數據
shell> sed -n '/^-- Current Database: `test_restore`/,/^-- Current Database:/p' mysql_back.sql
只提取建表語句
shell> sed -e'/./{H;$!d;}' -e 'x;/CREATE TABLE `test1`/!d;q' mysql_back.sql
只提取數據
shell> grep -i 'INSERT INTO `test1`' mysql_back.sql
提取所有建庫表語句
shell> grep -iv 'INSERT INTO `' mysql_back.sql
8. 導出數據
<select語句> into outfile "dest_file";
9. 導入數據
load data infile "<file_name>" into table <table_name>;
四、修改表的列與表名
1. 給列更名
alter table <表名稱> change <舊字段名稱> <新字段名稱>
2. 給表更名
alter table <舊表名稱> rename <新表名稱>
3. 修改某個表的字段類型及指定為空或非空
alter table <表名稱> change <字段名稱> <字段名稱> <字段類型> [not null];
alter table <表名稱> modify <字段名稱> <字段類型> [not null];
4. 增加一個字段(一列)
alter table 表名稱 add column 字段名稱 字段類型;
加在某個字段后面
alter table 表名稱 add column 字段名稱 字段類型 after 某個字段;
加在最前
alter table 表名稱 add column 字段名稱 字段類型 first;
5. 更改一個字段名字(也可以改變類型和默認值)
alter table <表名稱> change <原字段名稱> <新字段名稱 字段類型>;
6. 改變一個字段的默認值
alter table 表名稱 alter 字段名稱 set default 值;
該方法不會鎖表
7. 改變一個字段的數據類型
alter table <表名稱> change column <字段名稱> <字段名稱> <字段類型>;
8. 刪除字段
alter table <表名稱> drop column <列名>;
五 查詢表
SELECT [DISTINCT] <字段名稱,用逗號隔開/*> FROM <left_table> [<join_type> JOIN <right_table> ON <連接條件>] WHERE <where條件> GROUP BY <分組字段> HAVING <篩選條件> ORDER BY <排序條件> [desc/asc] LIMIT n[, m]
1. GROUP BY 與聚合函數 使用注意點
1 在不使用聚合函數的時候,group by 子句中必須包含所有的列,否則會報錯
正確: select name,age from test group by name,age; //和 select 一樣
2 在 group by 子句中不要加上聚合函數處的列名
2. having
SQL 標准
要求 having 必須引用 group 子句中的列或者用聚合函數處理過
后的列。
mysql 對這一標准進行了一些擴展,它允許 having 引
用 select 中檢索的列和外部查詢中的列。
having 中用到的條件要
么在 group by 中出現,要么在 select 的列中出現,要么在外查
詢中出現。
3. from
from 子查詢時要給數據表指定一個別名。from (select ..) [as] 別名 where...
4. union
select 語句 union [all] select 語句
union 會去重
5. join 外連接查詢
select * from tableA A [left、right] join tableB B on A.id = B.id
6. join 交叉連接
select * from tableA,tableB
select * from tableA cross join tableB
逗號與 cross join
區別是逗號不能使用 on
結果會有 n * n 條記錄(笛卡爾乘積)
7. join 內連接
select * from tableA A inner join tableB B on A.id = B.id
select * from tableA A inner join tableB B using(id)
using(字段)
可以合並相同字段,並且符合 A.id = B.id
內連接在沒有條件時和交叉連接沒有區別。
STRAIGHT_JOIN
可以手動指定驅動表
六 索引的創建、刪除和查看
1. 創建索引
方法一
-- 普通索引 ALTER TABLE 表名稱 ADD INDEX index_name (column_list) -- 唯一索引 ALTER TABLE 表名稱 ADD UNIQUE (column_list) -- 主鍵索引 ALTER TABLE 表名稱 ADD PRIMARY KEY (column_list)
方法二
CREATE INDEX index_name ON 表名稱 (column_list) CREATE UNIQUE INDEX index_name ON 表名稱 (column_list)
column_list 指出對哪些列進行索引,多列時各列之間用逗號分隔。
索引名index_name可選,缺省時,MySQL將根據第一個索引列賦一個名稱。
另外,ALTER TABLE允許在單個語句中更改多個表,因此可以在同時創建多個索引。
2. 刪除索引
-- 刪除索引 DROP INDEX index_name ON 表名稱; ALTER TABLE 表名稱 DROP INDEX index_name; -- 刪除主鍵 ALTER TABLE 表名稱 DROP PRIMARY KEY;
3. 查看索引
show index from 表名稱; show keys from 表名稱;
4. 手動選擇索引
USE INDEX
: 向優化器提示如何選擇索引IGNORE INDEX
: 忽略索引FORCE INDEX
: 強制使用索引
select * from tableA USE INDEX (key1, key2) where key1=1 and key2=2
七 外鍵
1. 增加外鍵
建表時
constraint 外鍵名 foreign key(外鍵字段) references 關聯表名(關聯字段);
修改表
alter table 表名 add constraint 外鍵名 foreign key(外鍵字段名) references 外表表名(對應的表的主鍵字段名);
2. 刪除外鍵
ALTER TABLE table-name DROP FOREIGN KEY key-id;
八 流程控制&函數
1 內置函數&方法
1.1 if
IF(expr1,expr2,expr3)
如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),則 IF()的返回值為expr2; 否則返回值則為 expr3。
1.2 CASE when
SELECT CASE 1 WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'more' END as testCol
1.3 IFNULL
IFNULL(expr1,expr2)
假如expr1 不為 NULL,則 IFNULL() 的返回值為 expr1; 否則其返回值為 expr2。
2 自定義存儲過程&函數
2.1 查看
查詢數據庫中的存儲過程和函數
- 存儲過程
show procedure status; select `name` from mysql.proc where db = '<dbname>' and `type` = 'PROCEDURE'; -- 函數 show function status; select `name` from mysql.proc where db = '<dbname>' and `type` = 'FUNCTION'
查看存儲過程或函數的創建代碼
show create procedure <proc_name>; show create function <func_name>;
九 視圖
1. 創建
create or replace view <視圖名>(<列名 1>,<列名 2>...) as <select 語句>;
2. 刪除
drop view <視圖 1> [,視圖 2....視圖 n];
十 觸發器
trigger_time: { BEFORE | AFTER } -- 事件之前還是之后觸發 trigger_event: { INSERT | UPDATE | DELETE } -- 三個類型 trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
假設定義一個觸發器,每次插入把 ctime
設為當前時間
delimiter // -- 更改結束符 create trigger <觸發器名字> before insert on <表名> for each row begin set new.ctime=now(); end;// delimiter ;
假設定義一個觸發器,每次更新把 mtime
設為當前時間
delimiter // -- 更改結束符 create trigger <觸發器名字> before update on <表名> for each row begin set new.mtime=now(); end;// delimiter ;
十一 查看狀態
# 查看狀態 status; show status; # innodb 狀態 show innodb status; # 查看參數 show variables like '%參數名稱%'; # 查看隔離級別 select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+
十二 導出導入
1. 導出到文件
select * into outfile 文件地址 [控制格式] form tableA;
導出到 csv,並壓縮
shell> mysql -B -u賬號 -p -e "SELECT語句" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" | gzip > data.csv.gz
控制格式同導入文件
2. 導入文件
load data infile 文件名 [replace|ignore] into table 表名 [控制格式]
replace
和ignore
: 表示對主鍵重復的數據處理方式- 控制格式
fields terminated by '\t' enclosed by '' escaped by '\\'
e.g.
SELECT * INTO OUTFILE '/tmp/data.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM tableA;
十三 統計語句
1. 計算最大可能使用內存
MySQL >= 8
select
(@@key_buffer_size + @@query_cache_size + @@tmp_table_size + @@innodb_buffer_pool_size + @@innodb_additional_mem_pool_size + @@innodb_log_buffer_size + @@max_connections * ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size+ @@join_buffer_size + @@binlog_cache_size + @@thread_stack ) )/1024/1024/1024 as max_mem_G;
MySQL < 8
select
(@@key_buffer_size + @@query_cache_size + @@tmp_table_size + @@innodb_buffer_pool_size + @@innodb_log_buffer_size + @@max_connections * ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size+ @@join_buffer_size + @@binlog_cache_size + @@thread_stack ) )/1024/1024/1024 as max_mem_G;
2. 數據大小
數據總大小
SELECT ROUND(SUM(DATA_LENGTH)/1024/1024/1024,2) as data_size_G,ROUND(SUM(INDEX_LENGTH)/1024/1024/1024,2) as index_G, ROUND(SUM(DATA_LENGTH+INDEX_LENGTH)/1024/1024/1024,2) as total_size_G,SUM(TABLE_ROWS) as rows FROM information_schema.TABLES;
某個庫大小
SELECT ROUND(SUM(DATA_LENGTH)/1024/1024/1024,2) as data_size_G,ROUND(SUM(INDEX_LENGTH)/1024/1024/1024,2) as index_G, ROUND(SUM(DATA_LENGTH+INDEX_LENGTH)/1024/1024/1024,2) as total_size_G,SUM(TABLE_ROWS) as rows FROM information_schema.TABLES WHERE TABLE_SCHEMA='庫名';
統計所有庫按大小排序
SELECT TABLE_SCHEMA, ROUND(SUM(DATA_LENGTH)/1024/1024/1024,2) as data_size_G,ROUND(SUM(INDEX_LENGTH)/1024/1024/1024,2) as index_G, ROUND(SUM(DATA_LENGTH+INDEX_LENGTH)/1024/1024/1024,2) as total_size_G,SUM(TABLE_ROWS) as rows FROM information_schema.TABLES group by TABLE_SCHEMA order by data_size_G desc;
3. 統計連接IP
select SUBSTRING_INDEX(host,':',1) as ip , count(*) from information_schema.processlist group by ip;
4. 查看鎖
mysql5.6
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; waiting_trx_id -- 請求的事物ID waiting_thread -- 請求的線程ID waiting_query -- 等待的SQL語句 blocking_trx_id -- 阻塞上面請求的事物的ID blocking_thread -- 阻塞的線程ID blocking_query -- 阻塞的當前的SQL,這個是無法看到的,除非SQL還沒有執行完成(不一定是該事物當中的最后一條SQL語句)
mysql5.7
select * from sys.innodb_lock_waits;
5. 查看沒有主鍵的表
SELECT table_schema, table_name FROM information_schema.TABLES WHERE table_name NOT IN ( SELECT DISTINCT TABLE_NAME FROM information_schema.COLUMNS WHERE COLUMN_KEY = 'PRI') AND table_schema NOT IN ('mysql' , 'information_schema','sys', 'performance_schema');
6. 索引合理性
SELECT t.TABLE_SCHEMA,t.TABLE_NAME,INDEX_NAME, CARDINALITY, TABLE_ROWS, CARDINALITY/TABLE_ROWS AS SELECTIVITY FROM information_schema.TABLES t, ( SELECT table_schema, table_name, index_name, cardinality FROM information_schema.STATISTICS WHERE (table_schema,table_name,index_name,seq_in_index) IN ( SELECT table_schema, table_name, index_name, MAX(seq_in_index) FROM information_schema.STATISTICS GROUP BY table_schema , table_name , index_name ) ) s WHERE t.table_schema = s.table_schema AND t.table_name = s.table_name AND t.table_schema = '數據庫名' -- 指定某一個庫名 ORDER BY SELECTIVITY;
- SELECTIVITY越接近1,越合理
- 因為聚合索引會在 statistics 表中產生多條數據,所以 MAX(seq_in_index) 可以拿到完整索引那條
7. 統計processlist各個狀態數量
shell> mysql -uroot -p<password> -e 'show processlist \G' | grep 'State:' | sort | uniq -c | sort -rn
十四 運維語句&命令
1. 更新統計信息
analyze table <table_name>;
2. 重新整理表
optimize table <table_name>;
3. 檢查表(MyISAM)
check table <table_name>;
4. 修復表(MyISAM)
repair table <table_name>;
5. 批量檢查或修復表
# 檢查所有表 shell> mysqlcheck -u root -p<password> -A -c # 修復所有表 shell> mysqlcheck -u root -p<password> -A -c
6. 統計每秒慢日志
shell> awk '/^# Time:/{print $3, $4, c;c=0}/^# User/{c++}' slowquery.log
7. 查看binlog日志
基於position
mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS --start-position=<start_pos> --stop-position=<stop_pos> <mysql binlog文件> > result.sql
基於時間點
mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS --start-datetime='<開始時間>' --stop-datetime='<結束時間>' <mysql binlog文件> > result.sql
查看某個pos的日志
mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS <mysql binlog文件> | grep -A '20' <pos>
8. 打開句柄數
統計各進程打開句柄數:
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr | head -n 10 # 某個進程 lsof -n|awk '$2=="<某個進程的PID>" {print $2}'|sort|uniq -c|sort -nr | head -n 10
統計各用戶打開句柄數
lsof -n|awk '{print $3}'|sort|uniq -c|sort -nr # mysql用戶 lsof -n|awk '$3 == "mysql" {print $3}'|sort|uniq -c|sort -nr
統計各命令打開句柄數
lsof -n|awk '{print $1}'|sort|uniq -c|sort -nr
9. 導出用戶權限(shell腳本)
#/bin/bash user='username' pass='password' sock='socket' expgrants() { mysql -B -u"${user}" -p"${pass}" -S"${sock}" -N $@ -e "SELECT CONCAT( 'SHOW CREATE USER ''', user, '''@''', host, ''';' ) AS query FROM mysql.user" | \ mysql -u"${user}" -p"${pass}" -S"${sock}" -f $@ | \ sed 's#$#;#g;s/^\(CREATE USER for .*\)/-- \1 /;/--/{x;p;x;}' mysql -B -u"${user}" -p"${pass}" -S"${sock}" -N $@ -e "SELECT CONCAT( 'SHOW GRANTS FOR ''', user, '''@''', host, ''';' ) AS query FROM mysql.user" | \ mysql -u"${user}" -p"${pass}" -S"${sock}" -f $@ | \ sed 's/\(GRANT .*\)/\1;/;s/^\(Grants for .*\)/-- \1 /;/--/{x;p;x;}' }
然后執行腳本
10. 批量殺連接
方法一
select concat('KILL ',id,';') from information_schema.processlist where user='某個用戶' into outfile '/tmp/kill.txt'; source /tmp/kill.txt;
方法二
mysqladmin -uroot -p processlist|awk -F "|" '{if($3 == "要殺的連接的用戶")print $2}'|xargs -n 1 mysqladmin -uroot -p kill