Appearance
MySQL 数据库完全指南
概述
MySQL 是世界上最流行的开源关系型数据库管理系统之一,由瑞典 MySQL AB 公司开发,现在由 Oracle 公司维护。MySQL 以其高性能、可靠性和易用性而闻名,广泛应用于 Web 应用程序、企业级应用和云服务中。
核心特性
- 开源免费:基于 GPL 许可证,社区版完全免费
- 跨平台:支持 Linux、Windows、macOS 等多种操作系统
- 高性能:优化的查询引擎,支持大规模并发访问
- 可扩展性:支持主从复制、分库分表等扩展方案
- ACID 兼容:支持事务处理,保证数据一致性
- 丰富的存储引擎:InnoDB、MyISAM、Memory 等多种存储引擎
版本演进
- MySQL 5.7:引入 JSON 数据类型、性能模式增强
- MySQL 8.0:窗口函数、CTE、角色管理、文档存储
- MySQL 8.1/8.2/8.3:持续性能优化和新特性
安装与配置
官方安装包安装
Linux (CentOS/RHEL)
bash
# 下载 MySQL 官方 Yum 仓库
wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo rpm -ivh mysql80-community-release-el7-3.noarch.rpm
# 安装 MySQL
sudo yum install mysql-server
# 启动 MySQL 服务
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 获取临时密码
sudo grep 'temporary password' /var/log/mysqld.log
# 安全配置
sudo mysql_secure_installation
Ubuntu/Debian
bash
# 更新包列表
sudo apt update
# 安装 MySQL
sudo apt install mysql-server
# 启动服务
sudo systemctl start mysql
sudo systemctl enable mysql
# 安全配置
sudo mysql_secure_installation
macOS
bash
# 使用 Homebrew
brew install mysql
# 启动服务
brew services start mysql
# 或者下载官方 DMG 安装包
# https://dev.mysql.com/downloads/mysql/
Docker 安装
bash
# 拉取 MySQL 镜像
docker pull mysql:8.0
# 运行 MySQL 容器
docker run --name mysql-server \
-e MYSQL_ROOT_PASSWORD=your_password \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
-d mysql:8.0
# 连接到 MySQL
docker exec -it mysql-server mysql -u root -p
Docker Compose
yaml
# docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql-server
environment:
MYSQL_ROOT_PASSWORD: your_password
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
command: --default-authentication-plugin=mysql_native_password
volumes:
mysql-data:
基本配置
配置文件位置
- Linux:
/etc/mysql/mysql.conf.d/mysqld.cnf
或/etc/my.cnf
- Windows:
C:\ProgramData\MySQL\MySQL Server 8.0\my.ini
- macOS:
/usr/local/etc/my.cnf
重要配置参数
ini
[mysqld]
# 基本设置
port = 3306
bind-address = 0.0.0.0
socket = /var/run/mysqld/mysqld.sock
# 字符集设置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# InnoDB 设置
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
# 查询缓存
query_cache_type = 1
query_cache_size = 64M
# 连接设置
max_connections = 200
max_connect_errors = 10
# 日志设置
log-error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# 二进制日志
log-bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7
数据类型
数值类型
sql
-- 整数类型
TINYINT -- 1字节,-128到127
SMALLINT -- 2字节,-32768到32767
MEDIUMINT -- 3字节,-8388608到8388607
INT -- 4字节,-2147483648到2147483647
BIGINT -- 8字节,-9223372036854775808到9223372036854775807
-- 浮点类型
FLOAT(M,D) -- 4字节单精度浮点
DOUBLE(M,D) -- 8字节双精度浮点
DECIMAL(M,D) -- 精确小数,用于货币计算
-- 示例
CREATE TABLE numbers (
id INT AUTO_INCREMENT PRIMARY KEY,
age TINYINT UNSIGNED,
salary DECIMAL(10,2),
score FLOAT(5,2)
);
字符串类型
sql
-- 定长字符串
CHAR(n) -- 固定长度,最大255字符
-- 变长字符串
VARCHAR(n) -- 可变长度,最大65535字符
-- 文本类型
TINYTEXT -- 最大255字符
TEXT -- 最大65535字符
MEDIUMTEXT -- 最大16777215字符
LONGTEXT -- 最大4294967295字符
-- 二进制类型
BINARY(n) -- 固定长度二进制
VARBINARY(n) -- 可变长度二进制
BLOB -- 二进制大对象
-- 示例
CREATE TABLE content (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
summary TEXT,
content LONGTEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
日期时间类型
sql
-- 日期时间类型
DATE -- 日期 'YYYY-MM-DD'
TIME -- 时间 'HH:MM:SS'
DATETIME -- 日期时间 'YYYY-MM-DD HH:MM:SS'
TIMESTAMP -- 时间戳,自动更新
YEAR -- 年份
-- 示例
CREATE TABLE events (
id INT AUTO_INCREMENT PRIMARY KEY,
event_name VARCHAR(100),
event_date DATE,
start_time TIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
JSON 类型 (MySQL 5.7+)
sql
-- JSON 数据类型
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
attributes JSON,
metadata JSON
);
-- 插入 JSON 数据
INSERT INTO products (name, attributes, metadata) VALUES
('iPhone 15',
'{"color": "blue", "storage": "128GB", "features": ["Face ID", "Wireless Charging"]}',
'{"manufacturer": "Apple", "release_year": 2023}');
-- 查询 JSON 数据
SELECT name,
JSON_EXTRACT(attributes, '$.color') as color,
JSON_EXTRACT(attributes, '$.storage') as storage
FROM products;
-- 使用 -> 操作符
SELECT name,
attributes->'$.color' as color,
attributes->>'$.storage' as storage
FROM products;
基本操作
数据库操作
sql
-- 创建数据库
CREATE DATABASE myapp
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 查看数据库
SHOW DATABASES;
-- 使用数据库
USE myapp;
-- 删除数据库
DROP DATABASE myapp;
-- 查看当前数据库
SELECT DATABASE();
表操作
sql
-- 创建表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
age INT CHECK (age >= 0 AND age <= 150),
status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_email (email),
INDEX idx_status (status)
);
-- 查看表结构
DESCRIBE users;
SHOW CREATE TABLE users;
-- 修改表结构
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users MODIFY COLUMN full_name VARCHAR(150);
ALTER TABLE users DROP COLUMN phone;
-- 重命名表
RENAME TABLE users TO app_users;
-- 删除表
DROP TABLE users;
CRUD 操作
插入数据
sql
-- 单行插入
INSERT INTO users (username, email, password_hash, full_name, age)
VALUES ('john_doe', 'john@example.com', 'hashed_password', 'John Doe', 30);
-- 多行插入
INSERT INTO users (username, email, password_hash, full_name, age) VALUES
('jane_smith', 'jane@example.com', 'hashed_password', 'Jane Smith', 25),
('bob_wilson', 'bob@example.com', 'hashed_password', 'Bob Wilson', 35),
('alice_brown', 'alice@example.com', 'hashed_password', 'Alice Brown', 28);
-- 插入或更新
INSERT INTO users (username, email, password_hash, full_name)
VALUES ('john_doe', 'john@example.com', 'new_password', 'John Doe')
ON DUPLICATE KEY UPDATE
password_hash = VALUES(password_hash),
updated_at = CURRENT_TIMESTAMP;
查询数据
sql
-- 基本查询
SELECT * FROM users;
SELECT username, email, full_name FROM users;
-- 条件查询
SELECT * FROM users WHERE age > 25;
SELECT * FROM users WHERE status = 'active' AND age BETWEEN 20 AND 40;
SELECT * FROM users WHERE username LIKE 'john%';
SELECT * FROM users WHERE email IN ('john@example.com', 'jane@example.com');
-- 排序和限制
SELECT * FROM users ORDER BY created_at DESC;
SELECT * FROM users ORDER BY age ASC, username DESC;
SELECT * FROM users LIMIT 10;
SELECT * FROM users LIMIT 10 OFFSET 20;
-- 聚合查询
SELECT COUNT(*) as total_users FROM users;
SELECT status, COUNT(*) as count FROM users GROUP BY status;
SELECT AVG(age) as average_age FROM users WHERE status = 'active';
SELECT MIN(age), MAX(age), AVG(age) FROM users;
-- 分组和过滤
SELECT status, COUNT(*) as count
FROM users
GROP BY status
HAVING count > 5;
更新数据
sql
-- 更新单行
UPDATE users
SET full_name = 'John Smith', age = 31
WHERE username = 'john_doe';
-- 批量更新
UPDATE users
SET status = 'inactive'
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
-- 条件更新
UPDATE users
SET age = age + 1
WHERE MONTH(created_at) = MONTH(CURDATE());
删除数据
sql
-- 删除特定记录
DELETE FROM users WHERE username = 'john_doe';
-- 批量删除
DELETE FROM users WHERE status = 'suspended';
-- 清空表
TRUNCATE TABLE users;
索引优化
索引类型
sql
-- 主键索引
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY
);
-- 唯一索引
CREATE UNIQUE INDEX idx_username ON users(username);
ALTER TABLE users ADD UNIQUE INDEX idx_email (email);
-- 普通索引
CREATE INDEX idx_age ON users(age);
CREATE INDEX idx_status ON users(status);
-- 复合索引
CREATE INDEX idx_status_age ON users(status, age);
CREATE INDEX idx_name_email ON users(full_name, email);
-- 前缀索引
CREATE INDEX idx_email_prefix ON users(email(10));
-- 函数索引 (MySQL 8.0+)
CREATE INDEX idx_upper_username ON users((UPPER(username)));
索引管理
sql
-- 查看索引
SHOW INDEX FROM users;
SHOW KEYS FROM users;
-- 删除索引
DROP INDEX idx_age ON users;
ALTER TABLE users DROP INDEX idx_status;
-- 重建索引
ALTER TABLE users DROP INDEX idx_status_age, ADD INDEX idx_status_age (status, age);
查询优化
执行计划分析
sql
-- 查看执行计划
EXPLAIN SELECT * FROM users WHERE age > 25;
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE status = 'active';
-- 分析查询性能
EXPLAIN ANALYZE SELECT * FROM users WHERE age BETWEEN 20 AND 40;
索引选择性分析
sql
-- 查看列数据分布比例,判断是否适合建索引
SELECT column_name, COUNT(1) as count
FROM information_schema.columns
WHERE table_schema = 'myapp' AND table_name = 'users'
GROUP BY column_name
ORDER BY count DESC;
-- 计算列的选择性
SELECT
COUNT(DISTINCT status) / COUNT(*) as status_selectivity,
COUNT(DISTINCT age) / COUNT(*) as age_selectivity,
COUNT(DISTINCT username) / COUNT(*) as username_selectivity
FROM users;
-- 分析索引使用情况
SELECT
table_schema,
table_name,
index_name,
cardinality,
ROUND(cardinality / (SELECT table_rows FROM information_schema.tables
WHERE table_schema = s.table_schema
AND table_name = s.table_name) * 100, 2) as selectivity
FROM information_schema.statistics s
WHERE table_schema = 'myapp' AND table_name = 'users'
ORDER BY selectivity DESC;
慢查询分析
sql
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
SET GLOBAL log_queries_not_using_indexes = 'ON';
-- 查看慢查询状态
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
-- 分析慢查询
-- 使用 mysqldumpslow 工具
-- mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
高级功能
存储引擎
InnoDB (默认)
sql
-- 创建 InnoDB 表
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
total_amount DECIMAL(10,2),
status ENUM('pending', 'paid', 'shipped', 'delivered'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB;
-- InnoDB 特性
-- 1. 支持事务 (ACID)
-- 2. 支持外键约束
-- 3. 行级锁定
-- 4. 崩溃恢复
-- 5. 多版本并发控制 (MVCC)
MyISAM
sql
-- 创建 MyISAM 表
CREATE TABLE logs (
id INT AUTO_INCREMENT PRIMARY KEY,
message TEXT,
level ENUM('info', 'warning', 'error'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=MyISAM;
-- MyISAM 特性
-- 1. 表级锁定
-- 2. 不支持事务
-- 3. 不支持外键
-- 4. 读取速度快
-- 5. 占用空间小
Memory
sql
-- 创建内存表
CREATE TABLE sessions (
session_id VARCHAR(128) PRIMARY KEY,
user_id INT,
data TEXT,
expires_at TIMESTAMP
) ENGINE=MEMORY;
-- Memory 特性
-- 1. 数据存储在内存中
-- 2. 访问速度极快
-- 3. 服务器重启数据丢失
-- 4. 适合临时数据和缓存
事务处理
sql
-- 基本事务
START TRANSACTION;
INSERT INTO orders (user_id, total_amount, status)
VALUES (1, 99.99, 'pending');
UPDATE users SET last_order_at = NOW() WHERE id = 1;
COMMIT;
-- 事务回滚
START TRANSACTION;
INSERT INTO orders (user_id, total_amount, status)
VALUES (1, 199.99, 'pending');
-- 发生错误时回滚
ROLLBACK;
-- 保存点
START TRANSACTION;
INSERT INTO orders (user_id, total_amount) VALUES (1, 50.00);
SAVEPOINT sp1;
INSERT INTO order_items (order_id, product_id, quantity) VALUES (LAST_INSERT_ID(), 1, 2);
SAVEPOINT sp2;
INSERT INTO order_items (order_id, product_id, quantity) VALUES (LAST_INSERT_ID(), 2, 1);
-- 回滚到保存点
ROLLBACK TO sp2;
COMMIT;
视图
sql
-- 创建视图
CREATE VIEW active_users AS
SELECT id, username, email, full_name, created_at
FROM users
WHERE status = 'active';
-- 复杂视图
CREATE VIEW user_order_summary AS
SELECT
u.id,
u.username,
u.email,
COUNT(o.id) as total_orders,
COALESCE(SUM(o.total_amount), 0) as total_spent,
MAX(o.created_at) as last_order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username, u.email;
-- 使用视图
SELECT * FROM active_users WHERE username LIKE 'john%';
SELECT * FROM user_order_summary ORDER BY total_spent DESC LIMIT 10;
-- 更新视图
CREATE OR REPLACE VIEW active_users AS
SELECT id, username, email, full_name, age, created_at
FROM users
WHERE status = 'active' AND age >= 18;
-- 删除视图
DROP VIEW active_users;
存储过程和函数
sql
-- 存储过程
DELIMITER //
CREATE PROCEDURE GetUserOrders(
IN user_id INT,
IN limit_count INT DEFAULT 10
)
BEGIN
SELECT
o.id,
o.total_amount,
o.status,
o.created_at
FROM orders o
WHERE o.user_id = user_id
ORDER BY o.created_at DESC
LIMIT limit_count;
END //
DELIMITER ;
-- 调用存储过程
CALL GetUserOrders(1, 5);
-- 存储函数
DELIMITER //
CREATE FUNCTION CalculateAge(birth_date DATE)
RETURNS INT
READS SQL DATA
DETERMINISTIC
BEGIN
RETURN YEAR(CURDATE()) - YEAR(birth_date) -
(DATE_FORMAT(CURDATE(), '%m%d') < DATE_FORMAT(birth_date, '%m%d'));
END //
DELIMITER ;
-- 使用函数
SELECT username, birth_date, CalculateAge(birth_date) as age
FROM users;
触发器
sql
-- 创建触发器
DELIMITER //
CREATE TRIGGER update_user_stats
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
UPDATE users
SET
total_orders = total_orders + 1,
total_spent = total_spent + NEW.total_amount,
last_order_at = NEW.created_at
WHERE id = NEW.user_id;
END //
DELIMITER ;
-- 删除订单时的触发器
DELIMITER //
CREATE TRIGGER update_user_stats_on_delete
AFTER DELETE ON orders
FOR EACH ROW
BEGIN
UPDATE users
SET
total_orders = total_orders - 1,
total_spent = total_spent - OLD.total_amount
WHERE id = OLD.user_id;
END //
DELIMITER ;
-- 查看触发器
SHOW TRIGGERS;
-- 删除触发器
DROP TRIGGER update_user_stats;
性能优化
查询优化技巧
sql
-- 1. 使用合适的索引
-- 避免在 WHERE 子句中使用函数
-- 不好的例子
SELECT * FROM users WHERE YEAR(created_at) = 2023;
-- 好的例子
SELECT * FROM users WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01';
-- 2. 避免 SELECT *
-- 不好的例子
SELECT * FROM users WHERE status = 'active';
-- 好的例子
SELECT id, username, email FROM users WHERE status = 'active';
-- 3. 使用 LIMIT
SELECT id, username FROM users ORDER BY created_at DESC LIMIT 20;
-- 4. 优化 JOIN 查询
-- 使用合适的 JOIN 类型
SELECT u.username, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
GROUP BY u.id, u.username;
-- 5. 使用 EXISTS 代替 IN (大数据集)
-- 不好的例子
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total_amount > 100);
-- 好的例子
SELECT * FROM users u WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.total_amount > 100
);
配置优化
ini
# my.cnf 性能优化配置
[mysqld]
# InnoDB 缓冲池大小 (建议设置为可用内存的 70-80%)
innodb_buffer_pool_size = 2G
# InnoDB 日志文件大小
innodb_log_file_size = 512M
innodb_log_buffer_size = 64M
# 查询缓存
query_cache_type = 1
query_cache_size = 128M
query_cache_limit = 2M
# 连接设置
max_connections = 500
max_connect_errors = 100
connect_timeout = 10
wait_timeout = 600
interactive_timeout = 600
# 表缓存
table_open_cache = 2000
table_definition_cache = 1000
# 临时表设置
tmp_table_size = 64M
max_heap_table_size = 64M
# 排序和分组
sort_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 2M
join_buffer_size = 2M
# 二进制日志
log-bin = mysql-bin
binlog_format = ROW
max_binlog_size = 100M
expire_logs_days = 7
# 慢查询日志
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1
监控和分析
sql
-- 查看数据库状态
SHOW STATUS;
SHOW STATUS LIKE 'Innodb%';
SHOW STATUS LIKE 'Threads%';
SHOW STATUS LIKE 'Queries';
-- 查看进程列表
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- 查看表状态
SHOW TABLE STATUS;
SHOW TABLE STATUS LIKE 'users';
-- 分析表
ANALYZE TABLE users;
OPTIMIZE TABLE users;
-- 检查表
CHECK TABLE users;
REPAIR TABLE users;
-- 查看索引使用情况
SELECT
table_schema,
table_name,
index_name,
cardinality,
sub_part,
packed,
nullable,
index_type
FROM information_schema.statistics
WHERE table_schema = 'myapp'
ORDER BY table_name, seq_in_index;
备份与恢复
逻辑备份
bash
# 备份单个数据库
mysqldump -u root -p myapp > myapp_backup.sql
# 备份多个数据库
mysqldump -u root -p --databases myapp testdb > multiple_backup.sql
# 备份所有数据库
mysqldump -u root -p --all-databases > all_databases_backup.sql
# 只备份表结构
mysqldump -u root -p --no-data myapp > myapp_structure.sql
# 只备份数据
mysqldump -u root -p --no-create-info myapp > myapp_data.sql
# 备份特定表
mysqldump -u root -p myapp users orders > specific_tables.sql
# 压缩备份
mysqldump -u root -p myapp | gzip > myapp_backup.sql.gz
# 恢复数据库
mysql -u root -p myapp < myapp_backup.sql
# 恢复压缩备份
gunzip < myapp_backup.sql.gz | mysql -u root -p myapp
物理备份
bash
# 使用 MySQL Enterprise Backup (商业版)
mysqlbackup --user=root --password --backup-dir=/backup/full backup
# 使用 Percona XtraBackup (开源)
# 安装 Percona XtraBackup
wget https://repo.percona.com/apt/percona-release_latest.generic_all.deb
sudo dpkg -i percona-release_latest.generic_all.deb
sudo apt update
sudo apt install percona-xtrabackup-80
# 全量备份
xtrabackup --user=root --password=your_password --backup --target-dir=/backup/full
# 准备备份
xtrabackup --prepare --target-dir=/backup/full
# 恢复备份
sudo systemctl stop mysql
xtrabackup --copy-back --target-dir=/backup/full
sudo chown -R mysql:mysql /var/lib/mysql
sudo systemctl start mysql
# 增量备份
xtrabackup --user=root --password=your_password --backup --target-dir=/backup/inc1 --incremental-basedir=/backup/full
自动化备份脚本
bash
#!/bin/bash
# mysql_backup.sh
# 配置变量
DB_USER="backup_user"
DB_PASS="backup_password"
DB_NAME="myapp"
BACKUP_DIR="/backup/mysql"
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql"
LOG_FILE="${BACKUP_DIR}/backup.log"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 执行备份
echo "$(date): Starting backup of $DB_NAME" >> $LOG_FILE
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME > $BACKUP_FILE
if [ $? -eq 0 ]; then
echo "$(date): Backup completed successfully" >> $LOG_FILE
# 压缩备份文件
gzip $BACKUP_FILE
# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
echo "$(date): Old backups cleaned up" >> $LOG_FILE
else
echo "$(date): Backup failed" >> $LOG_FILE
exit 1
fi
# 添加到 crontab
# 0 2 * * * /path/to/mysql_backup.sh
高可用性
主从复制
主服务器配置
ini
# 主服务器 my.cnf
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
# 创建复制用户
CREATE USER 'replication'@'%' IDENTIFIED BY 'replication_password';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%';
FLUSH PRIVILEGES;
# 查看主服务器状态
SHOW MASTER STATUS;
从服务器配置
ini
# 从服务器 my.cnf
[mysqld]
server-id = 2
relay-log = relay-bin
read_only = 1
gtid_mode = ON
enforce_gtid_consistency = ON
# 配置主从复制
CHANGE MASTER TO
MASTER_HOST='master_ip',
MASTER_USER='replication',
MASTER_PASSWORD='replication_password',
MASTER_AUTO_POSITION=1;
# 启动从服务器
START SLAVE;
# 查看从服务器状态
SHOW SLAVE STATUS\G
读写分离
python
# Python 读写分离示例
import pymysql
from pymysql.cursors import DictCursor
class DatabaseManager:
def __init__(self):
# 主数据库连接 (写)
self.master = pymysql.connect(
host='master_host',
user='app_user',
password='app_password',
database='myapp',
cursorclass=DictCursor
)
# 从数据库连接 (读)
self.slave = pymysql.connect(
host='slave_host',
user='app_user',
password='app_password',
database='myapp',
cursorclass=DictCursor
)
def execute_write(self, sql, params=None):
"""执行写操作"""
with self.master.cursor() as cursor:
cursor.execute(sql, params)
self.master.commit()
return cursor.lastrowid
def execute_read(self, sql, params=None):
"""执行读操作"""
with self.slave.cursor() as cursor:
cursor.execute(sql, params)
return cursor.fetchall()
# 使用示例
db = DatabaseManager()
# 写操作使用主库
user_id = db.execute_write(
"INSERT INTO users (username, email) VALUES (%s, %s)",
('john_doe', 'john@example.com')
)
# 读操作使用从库
users = db.execute_read("SELECT * FROM users WHERE status = %s", ('active',))
MySQL Cluster (NDB)
ini
# MySQL Cluster 配置示例
# config.ini (管理节点)
[ndbd default]
NoOfReplicas=2
DataMemory=80M
IndexMemory=18M
[ndbd]
hostname=node1.example.com
datadir=/var/lib/mysql-cluster
[ndbd]
hostname=node2.example.com
datadir=/var/lib/mysql-cluster
[mysqld]
hostname=sql1.example.com
[mysqld]
hostname=sql2.example.com
[ndb_mgmd]
hostname=mgm.example.com
datadir=/var/lib/mysql-cluster
安全性
用户管理
sql
-- 创建用户
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';
CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong_password';
-- 授权
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'app_user'@'localhost';
GRANT ALL PRIVILEGES ON myapp.* TO 'admin_user'@'localhost';
-- 查看权限
SHOW GRANTS FOR 'app_user'@'localhost';
-- 撤销权限
REVOKE DELETE ON myapp.* FROM 'app_user'@'localhost';
-- 修改密码
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'new_password';
-- 删除用户
DROP USER 'app_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
角色管理 (MySQL 8.0+)
sql
-- 创建角色
CREATE ROLE 'app_read', 'app_write', 'app_admin';
-- 给角色授权
GRANT SELECT ON myapp.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON myapp.* TO 'app_write';
GRANT ALL PRIVILEGES ON myapp.* TO 'app_admin';
-- 将角色分配给用户
GRANT 'app_read', 'app_write' TO 'app_user'@'localhost';
-- 设置默认角色
SET DEFAULT ROLE 'app_read', 'app_write' TO 'app_user'@'localhost';
-- 激活角色
SET ROLE 'app_read', 'app_write';
-- 查看当前角色
SELECT CURRENT_ROLE();
SSL/TLS 配置
ini
# my.cnf SSL 配置
[mysqld]
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem
require_secure_transport=ON
[client]
ssl-ca=/etc/mysql/ssl/ca-cert.pem
ssl-cert=/etc/mysql/ssl/client-cert.pem
ssl-key=/etc/mysql/ssl/client-key.pem
sql
-- 要求用户使用 SSL
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
ALTER USER 'existing_user'@'%' REQUIRE SSL;
-- 检查 SSL 状态
SHOW STATUS LIKE 'Ssl%';
SHOW VARIABLES LIKE 'have_ssl';
监控与运维
性能监控
sql
-- 查看连接信息
SHOW STATUS LIKE 'Connections';
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
-- 查看查询统计
SHOW STATUS LIKE 'Questions';
SHOW STATUS LIKE 'Queries';
SHOW STATUS LIKE 'Slow_queries';
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS;
-- 查看表锁信息
SHOW STATUS LIKE 'Table_locks%';
-- 查看查询缓存
SHOW STATUS LIKE 'Qcache%';
-- 性能模式查询
SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY sum_timer_wait DESC LIMIT 10;
SELECT * FROM performance_schema.file_summary_by_instance
WHERE file_name LIKE '%ibd'
ORDER BY sum_timer_read DESC LIMIT 10;
日志分析
bash
# 错误日志分析
tail -f /var/log/mysql/error.log
grep -i error /var/log/mysql/error.log
# 慢查询日志分析
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
# 二进制日志分析
mysqlbinlog mysql-bin.000001
mysqlbinlog --start-datetime="2023-01-01 00:00:00" --stop-datetime="2023-01-02 00:00:00" mysql-bin.000001
监控脚本
bash
#!/bin/bash
# mysql_monitor.sh
MYSQL_USER="monitor"
MYSQL_PASS="monitor_password"
LOG_FILE="/var/log/mysql_monitor.log"
# 检查 MySQL 服务状态
check_mysql_service() {
if systemctl is-active --quiet mysql; then
echo "$(date): MySQL service is running" >> $LOG_FILE
else
echo "$(date): MySQL service is down!" >> $LOG_FILE
# 发送告警
echo "MySQL service is down on $(hostname)" | mail -s "MySQL Alert" admin@example.com
fi
}
# 检查连接数
check_connections() {
CONNECTIONS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW STATUS LIKE 'Threads_connected';" | awk 'NR==2{print $2}')
MAX_CONNECTIONS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW VARIABLES LIKE 'max_connections';" | awk 'NR==2{print $2}')
USAGE_PERCENT=$((CONNECTIONS * 100 / MAX_CONNECTIONS))
if [ $USAGE_PERCENT -gt 80 ]; then
echo "$(date): High connection usage: $USAGE_PERCENT%" >> $LOG_FILE
fi
}
# 检查慢查询
check_slow_queries() {
SLOW_QUERIES=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW STATUS LIKE 'Slow_queries';" | awk 'NR==2{print $2}')
echo "$(date): Slow queries: $SLOW_QUERIES" >> $LOG_FILE
}
# 执行检查
check_mysql_service
check_connections
check_slow_queries
# 添加到 crontab
# */5 * * * * /path/to/mysql_monitor.sh
实际应用案例
电商系统数据库设计
sql
-- 用户表
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
phone VARCHAR(20),
birth_date DATE,
gender ENUM('M', 'F', 'Other'),
status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_email (email),
INDEX idx_status (status),
INDEX idx_created_at (created_at)
);
-- 商品表
CREATE TABLE products (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
description TEXT,
category_id INT NOT NULL,
brand_id INT,
sku VARCHAR(100) UNIQUE NOT NULL,
price DECIMAL(10,2) NOT NULL,
cost_price DECIMAL(10,2),
stock_quantity INT DEFAULT 0,
min_stock_level INT DEFAULT 0,
weight DECIMAL(8,2),
dimensions JSON,
attributes JSON,
status ENUM('active', 'inactive', 'discontinued') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_category (category_id),
INDEX idx_brand (brand_id),
INDEX idx_sku (sku),
INDEX idx_price (price),
INDEX idx_status (status),
FULLTEXT idx_name_desc (name, description)
);
-- 订单表
CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_number VARCHAR(50) UNIQUE NOT NULL,
user_id BIGINT NOT NULL,
status ENUM('pending', 'paid', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
total_amount DECIMAL(12,2) NOT NULL,
shipping_amount DECIMAL(8,2) DEFAULT 0,
tax_amount DECIMAL(8,2) DEFAULT 0,
discount_amount DECIMAL(8,2) DEFAULT 0,
payment_method ENUM('credit_card', 'debit_card', 'paypal', 'bank_transfer'),
shipping_address JSON,
billing_address JSON,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_order_number (order_number),
INDEX idx_status (status),
INDEX idx_created_at (created_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
);
-- 订单项表
CREATE TABLE order_items (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
total_price DECIMAL(12,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_order_id (order_id),
INDEX idx_product_id (product_id),
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
);
-- 购物车表
CREATE TABLE shopping_cart (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_user_product (user_id, product_id),
INDEX idx_user_id (user_id),
INDEX idx_product_id (product_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
);
分库分表策略
sql
-- 按用户 ID 分表的订单表
CREATE TABLE orders_0 LIKE orders;
CREATE TABLE orders_1 LIKE orders;
CREATE TABLE orders_2 LIKE orders;
CREATE TABLE orders_3 LIKE orders;
-- 分表路由函数
DELIMITER //
CREATE FUNCTION GetOrderTableName(user_id BIGINT)
RETURNS VARCHAR(20)
READS SQL DATA
DETERMINISTIC
BEGIN
DECLARE table_suffix INT;
SET table_suffix = user_id % 4;
RETURN CONCAT('orders_', table_suffix);
END //
DELIMITER ;
-- 应用层分表逻辑 (Python 示例)
# def get_order_table(user_id):
# return f"orders_{user_id % 4}"
#
# def insert_order(user_id, order_data):
# table_name = get_order_table(user_id)
# sql = f"INSERT INTO {table_name} (user_id, ...) VALUES (%s, ...)"
# cursor.execute(sql, (user_id, ...))
最佳实践
数据库设计原则
规范化设计
- 遵循第三范式,避免数据冗余
- 合理使用反规范化提升查询性能
- 使用合适的数据类型和长度
索引策略
- 为经常查询的列创建索引
- 避免过多索引影响写入性能
- 使用复合索引优化多条件查询
- 定期分析和优化索引
表设计
- 使用有意义的表名和列名
- 设置合适的主键策略
- 使用外键约束保证数据完整性
- 合理使用枚举类型
性能优化
查询优化
- 避免 SELECT *
- 使用 LIMIT 限制结果集
- 优化 JOIN 查询
- 使用合适的索引
配置优化
- 调整 InnoDB 缓冲池大小
- 优化连接参数
- 配置查询缓存
- 调整日志参数
硬件优化
- 使用 SSD 存储
- 增加内存容量
- 使用多核 CPU
- 优化网络配置
安全性
访问控制
- 使用最小权限原则
- 定期审查用户权限
- 使用强密码策略
- 启用 SSL/TLS 加密
数据保护
- 定期备份数据
- 测试恢复流程
- 加密敏感数据
- 审计数据库操作
运维管理
监控
- 监控服务器资源使用
- 监控数据库性能指标
- 设置告警机制
- 分析慢查询日志
维护
- 定期更新 MySQL 版本
- 优化表结构
- 清理无用数据
- 维护索引统计信息
总结
MySQL 作为世界上最流行的开源关系型数据库,具有以下优势:
- 成熟稳定:经过多年发展,功能完善,稳定性高
- 性能优秀:优化的查询引擎,支持大规模并发
- 生态丰富:丰富的工具和社区支持
- 易于使用:简单的安装配置,友好的管理界面
- 扩展性强:支持多种扩展方案,适应不同规模需求
通过合理的设计、优化和运维,MySQL 能够满足从小型应用到大型企业级系统的各种需求。掌握 MySQL 的核心概念、高级特性和最佳实践,是每个开发者和 DBA 的必备技能。
无论是 Web 应用开发、数据分析还是企业级系统建设,MySQL 都是一个值得信赖的选择。随着云计算和微服务架构的发展,MySQL 也在不断演进,为现代应用提供更好的支持。