旷世的忧伤

Huoty's Blog

MySQL 数据库基本使用指南

MySQL 是一个非常流行的小型关系型数据库管理系统。在数据库的管理上,通常会使用一些客户端工具,如 phpMyAdmin,navicat preminu,HeidiSQL, Sequal Pro,SQLyog,MySQL Workbench 等等。但有时候可能会无可避免的要用到命令行下的操作,本文旨在记录一些 MySQL 的基本使用方法,以及配置等。

安装与启动

如果是在 Ubuntu 系统中,使用 apt 工具安装完 MySQL 时会提示设置用户名和密码,如何没有设置,可以采用如下方式创建密码

mysqladmin -u root password “new_password”

使用包管理工具安装的 mysql 一般都会创建系统服务,以便于管理:

# 启动
sudo service mysql start

# 重启
sudo service mysql restart

# 停止
sudo service mysql stop

# 检查是否启动成功
ps -ef | grep mysqld

使用命令行客户端工具 登录到服务器 实现管理操作:

mysql -u root -P -p

登录成功后可以先尝试一些简单的操作:

# 列出数据库
show databases;

# 选择要操作的数据库,此后所有 mysql 命令皆只针对该数据库
use <database name>;

# 列出库中所有表(需先用 use 选择数据库)
show tables;

此外,也可以自行通过源码编译安装,这样的好处是可以做很多定制,缺点就是初始化、配置、启动等需要手动处理,比较麻烦。编译安装完成后需要先对数据库进行初始化:

# 初始化数据库,会在错误日志文件中生成随机密码
# 参数 --defaults-file 表示指定配置文件,否者会去默认位置查找
# 参数 --console 可以将错误日志输出到屏幕
bin/mysqld --defaults-file=my.cnf --initialize --console

# 使用 --initialize-insecure 参数可以生成无密码的 root 账户
bin/mysqld --defaults-file=my.cnf --initialize-insecure

在 5.7.7 之前没有 –initialize 参数,而是使用如下方式初始化:

scripts/mysql_install_db --defaults-file=my.cnf

启动推荐使用 mysqld_safe 命令,其增加了一些安全特性,以及一些额外的控制项, 如 –open-files-limit,–core-file-size 等。

bin/mysqld_safe –defaults-file=my.cnf

如果是编译安装的,首次登陆之后可能需要先修改密码。修改 root 密码的三种方式:

  • 用 mysqladmin 命令来改 root 用户口令
bin/mysqladmin --defaults-file=my.cnf -h 127.0.0.1 -u root password 'new-password'
  • 用 set password 命令来修改密码:
mysql> set password for root@localhost=password('new-password');
  • 直接修改 user 表的 root 用户口令:
mysql> use mysql;
mysql> update user set password=password('new-password') where user='root';
mysql> flush privileges;

MySQL8 之后使用如下方式修改 root 密码:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new-password';

从 MySQL8 开始,用户密码默认使用 caching_sha2_password 方式加密,目前大部分客户端还不支持 caching_sha2_password 插件,所以可能需要将密码改成 mysql_native_password 的机密方式:

myql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'new-password';

如果忘记了 root 密码,使用 –skip-grant-tables 参数以跳过密码认证方式启动服务器,再修改密码:

bin/mysqld --defaults-file=my.cnf --skip-grant-tables &

删除默认的数据库和用户,避免应存在漏洞而被注入攻击(test 库在 5.7 版本后默认没删除了):

mysql> drop database test;
mysql> delete from mysql.db;
mysql> delete from mysql.user where not(host="localhost" and user="root");
mysql> flush privileges;

基本配置

basedir:

该参数指定了安装 MySQL 的安装路径,填写全路径可以解决相对路径所造成的问题。例如:

basedir="/home/huoty/.local/mysql"

则表示 MySQL 安装在 /home/huoty/.local/mysql 路径下。

datadir:

该参数指定了 MySQL 的数据库文件的存放路径,即 MySQL data 文件位置。例如:

datadir="/home/huoty/.local/mysql/data"

sql_safe_updates:

以完全模式执行 SQL 语句,安全模式打开后,没有限制条件的更新语句(update,delete)将会被拒绝。设置方式为:

set [global] sql_safe_updates=1;

权限管理

创建用户

CREATE USER 'username'@'host' IDENTIFIED BY 'password';
  • username:需要创建的用户名
  • host:指定用户在哪个主机上可以登录,本地用户可用 localhost,允许从任意远程主机登录则使用通配符 %
  • password:用户的登录密码,密码可以为空,如果为空则该用户可以不需要密码登录服务器

示例:

CREATE USER 'user'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'user'@'192.168.1.101' IDENDIFIED BY '123456';
CREATE USER 'user'@'%' IDENTIFIED BY '123456';
CREATE USER 'user'@'%' IDENTIFIED BY '';
CREATE USER 'user'@'%';

# 指定 mysql_native_password 密码加密方式
CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

MySQL 8 开始,如果需要用 mysql_native_password 加密方式,需用如下方式创建用户:

CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

如果需要删除用户,使用 DROP USER 命令:

DROP USER 'username'@'host';

用户密码设置(修改)

SET PASSWORD FOR 'username'@'host' = PASSWORD('new-password');

示例:

SET PASSWORD FOR 'server'@'%' = PASSWORD("12345678");

如果是当前登录用户,可修改自己的密码:

SET PASSWORD = PASSWORD("new-password");

也可以使用 ALTER USER 修改用户密码:

# 修改用户密码
ALTER USER 'username'@'host' IDENTIFIED BY '123456';

# 修改当前用户密码
ALTER USER user() IDENTIFIED BY '123456';

# 修改密码加密规则
ALTER USER 'username'@'host' IDENTIFIED WITH mysql_native_password BY '123456';

# 使密码过期
ALTER USER 'username'@'host' IDENTIFIED BY '123456' PASSWORD EXPIRE;

# 设置密码永不过期
ALTER USER 'username'@'host' IDENTIFIED BY '123456' PASSWORD EXPIRE never;

# 设置过期时间为默认值
ALTER USER 'username'@'host' IDENTIFIED BY '123456' PASSWORD EXPIRE default;

# 指定过期时间间隔
ALTER USER 'username'@'host' IDENTIFIED BY '123456' PASSWORD EXPIRE interval 90 day;

授权用户

GRANT privileges ON databasename.tablename TO 'username'@'host' [WITH GRANT OPTION]
  • privileges:指定允许用户操作的权限,如 SELECT,INSERT,UPDATE 等,ALL 表示授予所权限
  • databasename:数据库名
  • tablename:表名,如果要授予该用户对所有数据库或表的相应操作权限则可用 * 表示,如 *.*
  • [with grant option]:表示该用户可将拥有的权限授予给其他用户(即权限传递)

常用的用户权限说明:

  • CREATE: 建立新的数据库或数据表
  • DROP: 删除数据表或数据库
  • ALTER: 修改已存在的数据表(例如增加/删除列)和索引
  • INDEX: 建立或删除索引
  • TRIGGER: 创建,删除,执行触发器
  • CREATE VIEW: 创建视图
  • CREATE TEMPOARY TABLES: 创建临时表
  • INSERT: 增加表的记录
  • DELETE: 删除表的记录
  • UPDATE: 修改表中已存在的记录
  • SELECT: 显示/搜索表的记录
  • PROCESS: 显示或杀死属于其它用户的服务线程
  • RELOAD: 重载访问控制表,刷新日志等
  • SHUTDOWN: 关闭MySQL服务
  • ALL: 允许做任何事(和 root 账户一样)
  • USAGE: 只允许登录(其它什么也不允许做)

示例:

GRANT SELECT, INSERT, UPDATE, CREATE ON *.* TO 'server'@'%';
GRANT ALL ON *.* TO 'admin'@'%';
GRANT SELECT ON test.* TO 'reader'@'%';
GRANT SELECT, UPDATE ON test.* TO 'user1'@'%';

撤销授权

REVOKE privilege ON databasename.tablename FROM 'username'@'host';

其中的 privilege, databasename, tablename 需与授权是相同才能生效。示例:

REVOKE SECECT ON test.* FROM 'reader'@'%';

权限查看

# 授权查看语法
SHOW GRANTS [FOR 'username'@'host'];

# 默认查看当前用户当前机器的权限
SHOW GRANTS;

# 查看指定用户和机器的权限
SHOW GRANTS FOR 'reader'@'localhost';
SHOW GRANTS FOR 'reader'@'192.168.3.%';

#  user 表中查看权限
SELECT * FROM mysql.user WHERE user='username' AND host='host' \G;

#  db 表中查看权限(可以看到用于对不同库的详细权限)
SELECT * FROM mysql.db WHERE user='username' AND host='host' \G;

基本操作

SHOW 语句使用:

# 查看所有支持的存储引擎
show engines;

# 查看 InnoDB 存储引擎状态
show engine innodb status;

# 系统特定资源的信息,如正在运行的线程数量
show status;
show status like '%connect%';
show status where `variable_name`='Threads_connected';

# 显示系统变量的名称和值
show variables;

# 显示服务器所支持的不同权限
show privileges;

# 查看用户权限
show grants for user_name;

# 列出所有数据库
show databases;

# 列出库中所有的表
use database; show tables;
show tables from database_name;

# 列出库中所有以 wp_ 开头的表
show tables from database_name like 'wp_%';
show tables in database_name like 'wp_%';

# 查看表中列的定义(表的属性,属性类型,主键信息,默认值等)
show columns from database_name.table_name;
show full columns from database_name.table_name;

# 查看当前数据库中表的信息
show table status;
show table status like '%name%';

# 查看表索引
show index from tablename;
show keys from tablename;

# 列出当前运行的线程任务
show processlist;
show full processlist;

# 查看警告或者错误日志
show warnings;
show errors;

# 查看 binlog
show master logs;
show master status;
show binlog events in 'mysql-bin.000003';

# 查看存储过程和函数的状态
SHOW { PROCEDURE | FUNCTION } STATUS [ LIKE 'pattern' ]

# 查看存储过程和函数的定义
SHOW CREATE { PROCEDURE | FUNCTION } sp_name

数据库操作:

创建数据库语法格式:

CREATE DATABASE [IF NOT EXISTS] <数据库名>
[[DEFAULT] CHARACTER SET <字符集名>]
[[DEFAULT] COLLATE <校对规则名>];

字符集(CHARACTER)和校对规则(COLLATION)是两个不同的概念,字符集用来定义 MySQL 存储字符串的方式,校对规则定义了比较字符串的方式。校对规则有 utf8_general_ci, utf8_unicode_ci, utf8_chinese_ci 等,utf8_general_ci 仅能够在字符之间进行逐个比较,所以其比较速度很快,但相对来说比较的正确性较差。

修改数据库全局数据的语法与创建的语法类似(不指定数据库名时操作默认选中的数据库):

ALTER DATABASE [数据库名] {
[ DEFAULT ] CHARACTER SET <字符集名> |
[ DEFAULT ] COLLATE <校对规则名>}

示例与其他操作:

# 创建数据库
create database 数据库名;
create database if exists 数据库名;

# 创建数据库时指定字符集和校对规则
CREATE DATABASE IF NOT EXISTS 数据库名
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;

# 修改数据库
ALTER DATABASE 数据库名
DEFAULT CHARACTER SET gb2312
DEFAULT COLLATE gb2312_chinese_ci;

# 查看数据库定义
SHOW CREATE DATABASE 数据库名;

# 重命名数据库
rename database 旧库名 TO 新库名;

# 删除数据库
drop database 数据库名;
drop database if exists 数据库名;

# 选择要操作的数据库
use 数据库名;

# 查看当前选中的数据库
select database();

表操作:

创建表的语法格式:

CREATE TABLE table_name (column_name column_type);

示例:

CREATE TABLE IF NOT EXISTS `test`(
   `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
   `name` VARCHAR(100) NOT NULL COMMENT '名字',
   `age` TINYINT NOT NULL COMMENT '年龄',
   `status` TINYINT NOT NULL DEFAULT '0' COMMENT '状态',
   `add_time` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '添加时间',
   `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (`id`)
   UNIQUE KEY `idx_name` (`name`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生信息表';

其他表操作:

# 查看表结构
desc 表名;
describe 表名;
show columns from 表名;

# 查看表信息
select table_name, table_type, engine, version, table_comment
from information_schema.tables
where table_schema='database_name' and table_name='table_name';

# 查看表字段信息
select table_name, column_name, data_type, is_nullable, column_default, column_comment
from information_schema.columns
where table_schema='database_name' and table_name='table_name';

# 清空表
delete from 表名;       # 自增 id 不会从 1 开始
truncate table 表名;    # 自增 id 会重新从 1 开始

# 删除表
drop table 表名;

# 重命名表
rename table 旧表 TO 新表
          [, 旧表 TO 新表] ...

# 修改表字段属性
alter table 表名 modify 字段名称 字段类型 [是否允许非空] comment '字段注释';

# 改变表字段属性(与 modify 类似,modify 用于微小改动,而 change 主要用于幅度较大的改动)
alter table 表名 change 字段原名称 字段新名称 字段类型 [是否允许非空] comment '字段注释';

# 添加字段
alter table 表名 add 字段名称 字段类型 [是否允许非空] comment '字段注释';

# 删除字段
alter table 表名 drop column 字段名称;

# 优化表(会锁表)
optimize table 表名

复制数据库:

先创建一个新的数据库:

create database newdb;

然后使用 mysqldump 命令工具导出 SQL 语句,再导入新的库

mysqldump -h 127.0.0.1 -u root olddb | mysql -h 127.0.0.1 -u root newdb

备份数据库:

一般用 mysqldump 把数据库备份到文件中。示例:

mysqldump -uroot -h127.0.0.1 -P3306 -p \
    --master-data=2 \
    --single-transaction \
    --routines \
    --triggers \
    --events \
	database [tables] > backup.sql

参数说明:

--single-transaction
    指定备份是在一个事务中完成,可以支持 innodb 存储引擎热备功能,对 innodb 可以不锁表进行热备,对于非 innodb 热备进行锁表

--triggers
    备份触发器

--routines
    备份存储过程和自定义函数

--events
    备份事件

--master-data
    该选项将 binlog 的位置和文件名追加到输出文件中。如果为 1,将会输出 CHANGE MASTER 命令;如果为 2,输出的 CHANGE  MASTER 命令前添加注释信息。该选项将打开 `--lock-all-tables` 选项,除非 `--single-transaction` 也被指定(在这种情况下,全局读锁在开始导出时获得很短的时间)。该选项自动关闭 `--lock-tables` 选项。

其他操作:

# 查看 mysql 版本
status;  #  \s; 等价
select version();

# 同时查看当前时间,用户名,数据库版本
select now(), user(), version();

# 查看当前连接的 ID
select connection_id();

binlog:

binlog 即二进制日志,其记录对数据发生或潜在发生更改的 SQL 语句,并以二进制的形式保存在磁盘中。二进制日志可以用来查看数据库的变更历史(具体的时间点所有的 SQL 操作)、数据库增量备份和恢复(增量备份和基于时间点的恢复)、Mysql 的复制(主主数据库的复制、主从数据库的复制)等。

二进制日志有三种格式,STATEMENT:基于SQL语句的复制(statement-based replication, SBR);ROW:基于行的复制(row-based replication, RBR);MIXED:混合模式复制(mixed-based replication, MBR)。

二进制日志的相关操作:

# 查看 binlog 相关配置
show variables like '%log_bin%';

# 查看 binlog 日志文件列表
show master logs;
show binary logs;

# 当前正在使用的 binlog 及当前日志位置
show master status;

# 查看 binlog 内容
show binlog events in 'mysql-bin.000005'

# 删除所有的binglog日志文件
reset master;

此外,还可以使用 mysqlbinlog 工具查看 binlog 内容:

mysqlbinlog –no-defaults log/mysql-bin.000007

线程列表

MySQL 可以使用 show processlist 来显示用户正在运行的线程,也可以使用 show full processlist。没有 full 时,只显示 SQL 表达式的前 100 个字符。需要注意的是,只有 root 用户能看到所有正在运行的线程,其他用户都只能看到自己正在运行的线程,看不到其它用户正在运行的线程。除非这个用户拥有 PROCESS 权限。

实际上 show processlist 显示的信息都是来自系统库 information_schema 中的 processlist 表。所以使用下面的查询语句可以获得相同的结果:

select * from information_schema.processlist

输出结果中各列的含义:

  • Id: 连接标识符,客户端连接 mysql 时系统分配的 ID,可通过 CONNECTION_ID() 函数查看。该 ID 记录在 INFORMATION_SCHEMA.PROCESSLIST 表中。该 ID 可用于 kill 语句中,以用于杀死某一查询语句
  • User: 当前连接的用户
  • Host: 当前连接的主机,便于确定哪个客户端正在做什么,显示方式为 host_name:client_port 的形式
  • db: 当前执行语句对应的默认数据库,如果选择了;否则为 NULL
  • Command: 显示这个线程此刻正在执行的命令,如休眠(sleep),查询(query),连接(connect)等
  • Time: 表示线程处于当前状态的时间长短,单位为秒
  • State: 显示使用当前连接的 SQL 语句的状态,其描述的是语句执行中的某一个状态。一个 SQL 语句,以查询为例,可能需要经过 COPYING to tmp table、sorting result、sending data 等状态才可以完成
  • Info: 包含由线程执行的语句的文本,如果连接没有执行任务语句则为 NULL。默认情况下,该列仅包含语句的前 100 个字符,要查看完整的语句,需使用 SHOW FULL PROCESSLIST

线程可以具有以下任何 Command 值(详细内容可见 Thread Command Values):

  • Binlog Dump: 这是主服务器上的线程,用于将二进制日志内容发送到从服务器
  • Table Dump: 线程将表内容发送到从服务器
  • Change user: 线程正在执行改变用户操作
  • Close stmt: 线程正在关闭准备好的语句
  • Connect: 复制中,从服务器连接到其主服务器
  • Connect Out: 复制中,从服务器正在连接到其主服务器
  • Create DB: 线程正在执行 create-database 操作
  • Daemon: 此线程在服务器内部,而不是服务客户端连接的线程
  • Debug: 线程正在生成调试信息
  • Delayed insert: 线程是一个延迟插入处理程序
  • Drop DB: 线程正在执行 drop-database 操作
  • Execute: 线程正在执行一个准备好的语句
  • Fetch: 线程正在执行一个准备语句的结果
  • Field List: 线程正在检索表列的信息
  • Init DB: 线程正在选择默认数据库
  • Kill: 线程正在杀死另一个线程
  • Long Data: 该线程在执行一个准备语句的结果中检索长数据
  • Ping: 线程正在处理服务器 ping 请求
  • Prepare: 线程正在为语句生成执行计划
  • Processlist: 线程正在生成有关服务器线程的信息
  • Query: 该线程正在执行一个语句
  • Quit: 线程正在终止
  • Refresh: 线程是刷新表,日志或缓存,或重置状态变量或复制服务器信息
  • Register Slave: 线程正在注册从服务器
  • Reset stmt: 线程正在重置一个准备好的语句
  • Set option: 线程正在设置或重置客户端语句执行选项
  • Shutdown: 线程正在关闭服务器
  • Sleep: 线程正在等待客户端向其发送新的语句
  • Statistics: 线程正在生成服务器状态信息
  • Time: 未使用

另外,线程的 State 值说明可以参考 General Thread States.

生成测试数据

要生成测试数据可以使用 存储过程。存储过程(Stored Procedure)是一组为了完成特定功能的 SQL 语句集通常的 SQL 语句在执行时需要要先编译,而存储过程是经编译后存储在数据库中,通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行。其语法格式:

DELIMITER $$
CREATE PROCEDURE procedure_name(parameter_list)
BEGIN
    parameter_body
END $$
DELIMITER ;

其中的 DELIMITER $$ 表示修改定界符。参数列表使用逗号分隔,参数入参数(IN)、输出参数(OUT)和输入/输出参数(INOUT)三种。存储过程的主体以 BEGIN 开始,以 END 结束。存储过程的名称默认在当前数据库中创建,若需要在特定数据库中创建存储过程,则需在名称前面加上数据库的名称,如 test.rand_string。

使用存储过程生成测试数据示例:

USE `test`;

CREATE TABLE IF NOT EXISTS `t_user` (
	`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(255) NOT NULL COMMENT '用户名',
	`euid` VARCHAR(64) NOT NULL COMMENT '有效用户ID(加密ID)',
	`passwd` VARCHAR(64) NOT NULL COMMENT '用户密码',
	`type` TINYINT NOT NULL DEFAULT '0' COMMENT '用户类型',
	`alias` VARCHAR(255) NULL DEFAULT '' COMMENT '用户昵称',
	`email` VARCHAR(64) NULL DEFAULT '' COMMENT '用户邮箱',
	`mobile` VARCHAR(16) NULL DEFAULT '' COMMENT '用户手机号',
	`intro` VARCHAR(255) NULL DEFAULT '' COMMENT '用户简介',
	`login_count` INT UNSIGNED NOT NULL DEFAULT '0' COMMENT '登录次数',
	`status` TINYINT NOT NULL DEFAULT '0' COMMENT '状态',
	`add_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
	`update_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
	KEY `idx_name` (`name`),
	UNIQUE KEY `idx_euid` (`euid`)
) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT = '用户信息表';

DELIMITER $$

CREATE PROCEDURE insert_test_data(IN num INT)
BEGIN
 	DECLARE i INT DEFAULT 0;

	WHILE i < num DO
		INSERT INTO `t_user` (`name`, `euid`, `passwd`, `type`, `status`) VALUES (
			lower(conv(floor(rand() * pow(2, 32)), 10, 36)),
			md5(uuid()),
			md5(rand()),
			floor(rand() * 7),
			floor(rand() * 4)
		);
		SET i = i + 1;
	END WHILE;
END$$

DELIMITER ;

CALL insert_test_data(1000000);
DROP PROCEDURE insert_test_data;

也可以通过一些 Web 工具生成测试数据,如:http://www.generatedata.com

命令行客户端

MySQL 提供了命令行客户端 mysql 命令也操作数据库,其常用参数如下:

-h, --host=name               指定数据库主机地址
-P, --port=#                  指定数据库端口
-u, --user=name               数据库用户名
-p, --password[=name]         数据库密码
-D, --database=name           指定数据库
-A, --no-auto-rehash          不预读数据库信息
-B, --batch                   不使用历史文件,禁用交互(即不支持自动补全)
--default-character-set=name  设置数据库的默认字符集
--column-type-info            结果集返回时,同时显示字段的类型等相关信息
-C, --compress                在客户端和服务器端传递信息时使用压缩
-e, --execute=name            直接执行 SQL 语句
-N, --skip-column-names       不显示列信息
--prompt=format_str           指定提示符,默认为 mysql>

实用脚本

#! /bin/bash

# Filename: _mysql.sh 2015-09-21
# Author: Huoty <sudohuoty@gmail.com>
# Script starts from here:

__mysql() {
    mysql -h localhost -u root --database test --password=123456
}

if [ "$*" != '' ] ; then
    echo "$*" | __mysql
else
    __mysql
fi

用该脚本可以直接在命令行执行 mysql 命令和 sql 语句,而不用进入 mysql 的交互式解释器。例如:

$ _mysql.sh "show tables"

$ _mysql.sh "select * from users"
Top