总结一些 MySQL 的常用命令
客户端
- Navicat 可视化工具
mysql-workbenchMySQL 官方的可视化开发和管理平台,ubuntu安装命令
snap connect mysql-workbench-community
snap connect mysql-workbench-community:password-manager-service
snap connect mysql-workbench-community:ssh-keys常用命令介绍
Where
where执行顺序是从左往右执行的,在数据量多的时候要考虑条件的先后顺序,应遵守一个原则:排除最多的条件放在第一个,即按照过滤数据由大到小排序 where- where 中 AND 的执行优先级高于 OR,即在 AND、OR 同时出现时,优先执行 AND 语句,再执行 OR 语句
MySQL 的最左前缀原则 (Leftmost Prefix Principle) 是关于**复合索引(Composite Index)**如何被查询使用的核心规则。理解这个原则对于优化涉及多列的 WHERE 子句至关重要。
当你在多列上创建了一个复合索引(例如 INDEX idx_name (col1, col2, col3))时:
- 索引实际上是按顺序存储的: 索引数据首先按
col1排序,在col1相等的情况下,再按col2排序,最后在col1和col2都相等的情况下,才按col3排序。 - 最左前缀原则规定: 只有从索引的最左边的列开始,连续匹配查询条件时,索引才会被有效使用。
假设你在表 T 上创建了一个复合索引:INDEX idx_abc (a, b, c)
| 查询条件 | 是否使用索引? | 原因 |
|---|---|---|
| WHERE a = 1 | 是(全匹配) | 匹配了最左边的 a。 |
| WHERE a = 1 AND b = 2 | 是(全匹配) | 匹配了最左边的 a 和 b。 |
| WHERE a = 1 AND b = 2 AND c = 3 | 是(全匹配) | 匹配了整个索引 (a, b, c)。 |
| WHERE a = 1 AND c = 3 | 是(仅 a) | 匹配了最左边的 a。索引只能用到 a 部分,后面的 c 部分无法利用(相当于 a 过滤后,再在结果中扫描 c)。 |
| WHERE b = 2 AND c = 3 | 否 | 跳过了索引的第一列 a。索引的查找必须从 a 开始。 |
| WHERE c = 3 | 否 | 跳过了 a 和 b。 |
| WHERE a > 1 AND b = 2 | 部分(仅 a) | a 是范围查询 (> 或 LIKE ‘%…’ 或 BETWEEN) 时,通常会中断索引的连续性。索引只能用到 a,后面的 b 就不能使用了。 |
- 核心要点
- 顺序不能跳跃: 你不能跳过索引前缀中的任何列。如果你只查询
col1和col3,那么col3部分的索引是无效的。 - 顺序可以颠倒(但非必需): 对于
AND条件,MySQL 的查询优化器通常非常智能,它会自行重排查询条件以匹配索引顺序。例如,对于索引 (a, b),查询 WHERE b = 2 AND a = 1 仍然会充分使用索引,因为优化器会将其视为 WHERE a = 1 AND b = 2。 - 范围查询中断: 当查询条件中出现范围查询(例如 >, <, LIKE ‘abc%’, BETWEEN 时,索引的使用通常会在这一列停止。范围条件之后的索引列将无法继续用于快速定位数据。
优化建议:在设计复合索引时,应将最常用于查询、且最具选择性(基数高,能过滤掉最多数据)的列放在索引的最左边。
HAVING
在 MySQL 中,HAVING 子句用于对 GROUP BY 分组后的结果进行过滤。它与 WHERE 子句的关键区别在于:
WHERE在分组前过滤数据,而HAVING在分组后过滤数据HAVING通常与聚合函数(如SUM,AVG,COUNT,MAX,MIN)一起使用
基础语法
SELECT column1, aggregate_function(column2)
FROM table
WHERE condition -- 分组前的筛选
GROUP BY column1
HAVING condition; -- 分组后的筛选示例:查询订单数超过 5 次的客户及其订单数量
SELECT customer_id, COUNT(order_id) AS total_orders
FROM orders
GROUP BY customer_id
HAVING total_orders > 5;HAVING vs WHERE:
| 特性 | WHERE |
HAVING |
|---|---|---|
| 执行顺序 | 在 GROUP BY 前过滤数据 |
在 GROUP BY 后过滤分组结果 |
| 可用的条件 | 不能直接使用聚合函数 | 可以直接使用聚合函数 |
| 性能优化 | 优先用 WHERE 减少分组数据量 |
仅用于分组后的过滤 |
ALTER
-- 更改数据库字符集
ALTER DATABASE [database_name]
CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-- 更改表字符集
ALTER TABLE [table_name]
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- Change a column
ALTER TABLE [table_name]
CHANGE [column_name] [column_name] VARCHAR(255)
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 调整表字段顺序
ALTER TABLE [table_name]
CHANGE COLUMN `x1` `x1` LONGTEXT NULL DEFAULT NULL AFTER `x2`;- 配置字符集
- ALTER TABLE 的锁
- MySQL 5.6 之前的版本,整个 DDL 过程的就是全程锁表
- MySQL 5.6 之后的版本,新增
ONLINE DDL的功能,大大减少锁表时间-
- 原始表加写锁
-
- 按照原始表和执行语句的定义,重新定义一个空的临时表,并申请 rowlog 的空间
-
- 拷贝原表数据到临时表,此时的表数据修改操作(增删改)都会存放在 rowlog 中。此时该表客户端可以进行操作的
-
- 原始表数据全部拷贝完成后,会将 rowlog 中的改动全部同步到临时表,这个过程客户端是不能操作的
-
- 当原始表中的所有记录都被 Copy 临时表,并且 Copy 期间客户端的所有增删改操作都同步到临时表。再将临时表命名为原始表表名
-
- 耗时经验值:
- 16 核 32G 500w 数据 ALTER TABLE 加字段时,不加 default 65s,加 default 220s,锁表时间占后 50%左右
optimize table
delete from table_name 之后,表会产生大量的碎片空间,使用 optimize table 可以释放该空间碎片
OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL]
TABLE tbl_name [, tbl_name] ...
- 一般输出 Table does not support optimize, doing recreate + analyze instead,等价于 `alter table <table_name> ENGINE=InnoDB`optimize table后.ibd文件的空间与 mysqldump 的大小基本持平- 900w 数据,20G 表空间,耗时 650s,锁部分时间很短,基本不影响表的插入
- 参考
DELETE
DELETE 语句的锁定行为主要包括两个方面
表级锁(Table Locking)不添加限定条件时产生(不推荐)行级锁(Row Locking)添加限定条件,如 where、limit 等时出现,推荐删除数据时指定
rename 重命名表
# rename
rename table <old-table-name> to <new-table-name>;
# aalter
alter table <old-table-name> rename as <new-table-name>;json_extract 处理 json 字段
- MySQL 5.7+ 开始提供
json_extract函数 - 格式
$.字段名可以用来查询对应的 valuejson_extract('字段', '$.key')json 对象json_extract('字段', '$[数组下标].key')json 数组
JSON_EXTRACT(json_doc, path[, path] …)- 示例
# 创建数据库
create database test;
use test
# 创建表
CREATE TABLE `json_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`value` json DEFAULT NULL COMMENT 'json value',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 表结构
mysql> desc json_table;
+-------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| value | json | YES | | NULL | |
+-------+------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> show create table json_table;
+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| json_table | CREATE TABLE `json_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`value` json DEFAULT NULL COMMENT 'json value',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 |
+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
# 插入数据
insert into `json_table` values (1, '{"name": "xie", "age": 18}');
insert into `json_table` values (2, '{"name": "xianbin", "site": "https://www.xiexianbin.cn"}');
# 查询所有字段
mysql> select * from json_table;
+----+----------------------------------------------------------+
| id | value |
+----+----------------------------------------------------------+
| 1 | {"age": 18, "name": "xie"} |
| 2 | {"name": "xianbin", "site": "https://www.xiexianbin.cn"} |
+----+----------------------------------------------------------+
2 rows in set (0.00 sec)
# 简单示例
mysql> select json_extract('{"name":"xianbin","age":"18"}', "$.age");
+-------------------------------------------------------+
| json_extract('{"name":"xianbin","age":"18"}',"$.age") |
+-------------------------------------------------------+
| "18" |
+-------------------------------------------------------+
1 row in set (0.00 sec)
# 查询 json 的 name 字段
mysql> select json_extract(`value`, '$.name') from `json_table`;
+---------------------------------+
| json_extract(`value`, '$.name') |
+---------------------------------+
| "xie" |
| "xianbin" |
+---------------------------------+
2 rows in set (0.00 sec)
# 默认值为 NULL
mysql> select json_extract(`value`, '$.name') as `name`, json_extract(`value`, '$.site') as `site` from `json_table`;
+-----------+-----------------------------+
| name | site |
+-----------+-----------------------------+
| "xie" | NULL |
| "xianbin" | "https://www.xiexianbin.cn" |
+-----------+-----------------------------+
2 rows in set (0.00 sec)
# 数组示例
mysql> insert into `json_table` values (3, '[{"name": "xiexianbin", "site": "https://www.xiexianbin.cn"}]');
# 查询数据的内容
mysql> select json_extract(`value`, '$[0].name') from `json_table` where id = 3;
+------------------------------------+
| json_extract(`value`, '$[0].name') |
+------------------------------------+
| "xiexianbin" |
+------------------------------------+
1 row in set (0.00 sec)
# json 查询条件
mysql> select * from `json_table` where json_extract(`value`, '$.name') = 'xianbin';
+----+----------------------------------------------------------+
| id | value |
+----+----------------------------------------------------------+
| 2 | {"name": "xianbin", "site": "https://www.xiexianbin.cn"} |
+----+----------------------------------------------------------+
1 row in set (0.00 sec)RETURNING
- 生效版本
- MySQL 5.7 20210330 及以上
- MySQL 8.0 20220330 及以上
- 使用
DELETE...RETURNING语句返回前镜像数据INSERT/REPLACE...RETURNING返回后镜像数据
USE INDEX
使用 USE INDEX 指示查询优化器使用查询的命名索引列表
SELECT select_list
FROM <table_name>
USE INDEX(<index1, index2, ...>)
-- IGNORE
-- FORCE INDEX
WHERE <condition>;查看索引
SHOW INDEXES FROM <table_name>;show processlist
show processlist;
# 等价于
select * from information_schema.processlist where User='UserName';
# 生成杀死进程的命令
select concat('kill ',ID,';') from information_schema.processlist where User='UserName';
# 监控统计每个用户的访问
select User,count(*) as cnt from information_schema.processlist group by user;show processlist;查看当前所有数据库连接的session状态,非 root 用户仅能看到自己正在运行的线程(也可以配置权限)
mysql> show processlist;
+----+-----------------+-----------+------+---------+------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+------+---------+------+------------------------+------------------+
| 5 | event_scheduler | localhost | NULL | Daemon | 28 | Waiting on empty queue | NULL |
| 10 | root | localhost | NULL | Query | 0 | init | show processlist |
+----+-----------------+-----------+------+---------+------+------------------------+------------------+
2 rows in set (0.00 sec)说明:
Id线程的唯一标识,可以通过kill <id>命令杀掉线程- 本质为
information_schema.processlist表的主键
- 本质为
User启动该线程的用户Host发送请求的客户端的 IP 和 端口号db当前执行的命令的数据库上- 未指定数据库该值为 NULL
Command此刻该线程正在执行的命令,参考
Time该线程运行到该状态的时间State线程运行Command当前的状态,参考
Info一般记录的是线程执行的语句- 默认只显示前 100 个字符,查看全部信息可使用
SHOW FULL PROCESSLIST\G;
- 默认只显示前 100 个字符,查看全部信息可使用
- 从数据库查询(等价的命令)
select * from information_schema.processlist;
select * from information_schema.processlist where User='UserName';
# 生成 kill 的命令
select concat('kill ',ID,';') from information_schema.processlist where User='UserName';
# 统计用户的连接数量
select User, count(*) as cnt from information_schema.processlist group by user;免密码登录
方法一
[root@xiexianbin_cn ~]# cat .my.cnf
[client]
user=root
password=pass方法二
mysql -uroot -S /var/lib/mysql/mysql.sock用户
GRANT 语法
# 赋权
GRANT privileges (columns)
ON what
TO user IDENTIFIED BY "password"
WITH GRANT OPTION
# 写入、刷新权限
FLUSH PRIVILEGES;
# 查询
show grants for <user>;- 权限列表
ALL所有权限,ALL PRIVILEGES 同义词ALTER修改表和索引CREATE创建数据库和表DELETE删除表中已有的记录DROP抛弃(删除)数据库和表INDEX创建或抛弃索引INSERT向表中插入新行REFERENCE未用SELECT检索表中的记录UPDATE修改现存表记录FILE读或写服务器上的文件PROCESS查看服务器中执行的线程信息或杀死线程RELOAD重载授权表或清空日志、主机缓存或表缓存SHUTDOWN关闭服务器USAGE特殊的无权限权限
创建用户
GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'root';
GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
GRANT ALL ON test.* TO 'root'@'%' IDENTIFIED BY 'test';
GRANT ALL ON test.* TO 'root'@'localhost' IDENTIFIED BY 'test' WITH GRANT OPTION;
FLUSH PRIVILEGES;
GRANT SElECT ON test.* TO 'root'@'${ip}' IDENTIFIED BY "test";
FLUSH PRIVILEGES;
# 权限回收
REVOKE all ON *.* FROM 'root'@'localhost';用户权限
show grants for itat@‘%';数据库与表
查看数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| data1 |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.01 sec)
创建数据库
CREATE DATABASE IF NOT EXISTS data1 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
mysql> create database date2;
Query OK, 1 row affected (0.01 sec)
mysql -uroot -proot -Dmysql -e "select host,user from user";for name in a b c; do
mysql -uroot -proot -Dmysql -e"CREATE DATABASE IF NOT EXISTS ${name}_t DEFAULT CHARSET utf8 COLLATE utf8_general_ci;";
mysql -uroot -proot -Dmysql -e"CREATE DATABASE IF NOT EXISTS ${name}_o DEFAULT CHARSET utf8 COLLATE utf8_general_ci;";
done
mysql -uroot -proot -e "show databases"删除数据库
drop database data1;创建表
CREATE TABLE training(
id INT(11) PRIMARY KEY,
col1 VARCHAR(20) NOT NULL,
START DATE);查看表创建命令
mysql> show create table t_config \G
*************************** 1. row ***************************
Table: t_config
Create Table: CREATE TABLE `t_config` (
`id` int(11) NOT NULL,
`col2` varchar(36) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)其他
查看 mysql 服务器数据文件
show variables like '%datadir%';查看 mysql 版本
show variables like '%version%';查看系统变量控制二进制日志自动删除的天数
show variables like 'expire_log%';
set global expire_logs_days=7;
select @@expire_logs_days;查看 MySQL 支持的存储引擎
show engines;查看 innodb 的状态
show engine innodb status;表拆分示例
create table hpc_job_table_2021_1231 like hpc_job_table;
insert into hpc_job_table_2021_1231 select * from hpc_job_table where time_end < "2021-12-31";
delete from hpc_job_table where time_end < "2021-12-31";查看 mysql 库各表容量大小
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='mysql'
order by data_length desc, index_length desc;
select concat(round(sum(data_length/1024/1024),2),'MB') as data_length_MB, concat(round(sum(index_length/1024/1024),2),'MB') as index_length_MB
from tables
where table_schema='passport' and table_name='tb_user_info';innochecksum
innochecksum 是一个用于校验 innodb 表空间文件完整性的工具
- innnchecksum 使用时必须关闭 mysqld 进程,否则会在使用的时候提示
Unable to lock file的错误 - 使用场景:mysqld 进程异常退出,或服务器宕机时用于快速检查表空间文件的完整性
使用
innochecksum --count <table>.ibd # ibd 文件中共有多少个page
innochecksum --page-type-summary sbtest1.ibd
innochecksum --page-type-dump=/tmp/<table>.log sbtest1.ibd备份账号信息
SELECT
CONCAT(
'create user \'',
user,
'\'@\'',
Host,
'\''
' IDENTIFIED BY PASSWORD \'',
authentication_string,
'\';'
) AS CreateUserQuery
FROM
mysql.`user`
WHERE
`User` NOT IN (
'mysql.session',
'mysql.sys'
);- 导出脚本(参考)
#!/bin/bash
#Function export user privileges
pwd=root
expgrants()
{
mysql -B -u'root' -p${pwd} -N $@ -e "SELECT CONCAT( 'SHOW GRANTS FOR ''', user, '''@''', host, ''';' ) AS query FROM mysql.user" | \
mysql -u'root' -p${pwd} $@ | \
sed 's/\(GRANT .*\)/\1;/;s/^\(Grants for .*\)/-- \1 /;/--/{x;p;x;}'
}
expgrants > /tmp/grants.sql
echo "flush privileges;" >> /tmp/grants.sql
#执行脚本后结果
-- Grants for read@%
GRANT SELECT ON *.* TO 'read'@'%';
-- Grants for root@%
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
-- Grants for test@%
GRANT USAGE ON *.* TO 'test'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, EXECUTE, CREATE VIEW, SHOW VIEW ON `test_db`.* TO 'test'@'%';
-- Grants for test_user@%
GRANT USAGE ON *.* TO 'test_user'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON `test_db`.`t1` TO 'test_user'@'%';
-- Grants for mysql.session@localhost
GRANT SUPER ON *.* TO 'mysql.session'@'localhost';
GRANT SELECT ON `performance_schema`.* TO 'mysql.session'@'localhost';
GRANT SELECT ON `mysql`.`user` TO 'mysql.session'@'localhost';
-- Grants for mysql.sys@localhost
GRANT USAGE ON *.* TO 'mysql.sys'@'localhost';
GRANT TRIGGER ON `sys`.* TO 'mysql.sys'@'localhost';
GRANT SELECT ON `sys`.`sys_config` TO 'mysql.sys'@'localhost';禁止库写入
# 对库生效
FLUSH TABLES WITH READ LOCK;
UNLOCK TABLES;
# 对表生效
LOCK TABLES table_name READ;最近更新
最新评论