一、数据库操作
1.1 创建与管理
sql
-- 基本语法
CREATE DATABASE database_name;
-- 完整语法(指定字符集和排序规则)
-- 推荐使用 utf8mb4 以支持 emoji 和所有 Unicode 字符
CREATE DATABASE database_name
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci; -- 或 utf8mb4_general_ci (性能稍好,但排序精度稍低)
-- 如果不存在则创建(避免报错)
CREATE DATABASE IF NOT EXISTS database_name;
-- 查看所有数据库
SHOW DATABASES;
-- 选择/切换数据库
USE database_name;
-- 查看当前数据库
SELECT DATABASE();
-- 删除数据库
DROP DATABASE database_name;
DROP DATABASE IF EXISTS database_name;
1.2 修改数据库
sql
-- 修改数据库字符集(注意:此操作不会转换已有表的字符集)
ALTER DATABASE database_name
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
二、表操作
2.1 数据类型(补充)
| 分类 | 类型 | 说明 |
|---|---|---|
| 整数 | TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT |
可选 UNSIGNED(无符号),INT(11) 中的 11 仅为显示宽度,与存储大小无关 |
| 小数 | DECIMAL(M,D), FLOAT, DOUBLE |
DECIMAL 用于精确计算(如金额),M是总位数,D是小数位数 |
| 字符串 | CHAR(n), VARCHAR(n), TEXT, LONGTEXT |
VARCHAR 变长,节省空间;TEXT 类型不能有默认值 |
| 日期时间 | DATE, TIME, DATETIME, TIMESTAMP, YEAR |
TIMESTAMP 受时区影响,范围较小;DATETIME 范围大,不受时区影响 |
| 二进制 | BLOB, LONGBLOB, BINARY, VARBINARY |
存储图片、文件等二进制数据 |
| 枚举 | ENUM('a','b','c') |
单选,内部存储为整数,最多 65535 个成员 |
| 集合 | SET('a','b','c') |
多选,最多 64 个成员 |
| JSON | JSON |
MySQL 5.7+ 支持,提供高效的 JSON 文档存储和查询 |
| 空间数据 | GEOMETRY, POINT, LINESTRING, POLYGON |
用于地理空间数据 |
2.2 创建表(增强)
sql
-- 完整示例(包含更多约束和选项)
CREATE TABLE IF NOT EXISTS users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
username VARCHAR(50) NOT NULL COMMENT '用户名',
email VARCHAR(100) NOT NULL COMMENT '邮箱',
age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄',
status ENUM('active', 'inactive', 'banned') NOT NULL DEFAULT 'active' COMMENT '状态',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-- 约束
PRIMARY KEY (id),
UNIQUE KEY uk_username (username),
UNIQUE KEY uk_email (email),
INDEX idx_status_age (status, age), -- 复合索引
-- 外键约束
-- ON DELETE CASCADE: 主表删除时,从表关联行也删除
-- ON DELETE SET NULL: 主表删除时,从表关联字段设为NULL
-- ON UPDATE CASCADE: 主表主键更新时,从表关联字段也更新
FOREIGN KEY (dept_id) REFERENCES departments(id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
-- 分区表(适用于大数据量)
CREATE TABLE sales_log (
id INT AUTO_INCREMENT,
sale_date DATE NOT NULL,
amount DECIMAL(10, 2),
PRIMARY KEY (id, sale_date) -- 分区键必须是主键的一部分
)
PARTITION BY RANGE (YEAR(sale_date)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025)
);
-- 创建表时指定存储引擎和字符集
-- ENGINE=InnoDB (支持事务、行锁、外键)
-- ENGINE=MyISAM (不支持事务,表锁,全文索引,旧版本默认)
-- ENGINE=Memory (数据存于内存,速度快,重启后丢失)
2.3 修改表
sql
-- 修改表名
ALTER TABLE old_name RENAME TO new_name;
RENAME TABLE old_name TO new_name;
-- 修改列(重命名+改类型+改约束)
ALTER TABLE table_name CHANGE old_col_name new_col_name new_datatype [NOT NULL] [DEFAULT 'value'];
-- 仅修改列的约束或默认值(比 CHANGE 更高效)
ALTER TABLE table_name MODIFY col_name datatype NOT NULL DEFAULT 'new_default';
-- 添加/删除外键
ALTER TABLE table_name ADD CONSTRAINT fk_name FOREIGN KEY (col) REFERENCES other_table(id);
ALTER TABLE table_name DROP FOREIGN KEY fk_name;
-- 表选项
ALTER TABLE table_name ROW_FORMAT=DYNAMIC; -- 优化行存储格式
ALTER TABLE table_name COMMENT = '新的表注释';
三、数据操作(CRUD)
3.1 插入数据 (INSERT)
sql
-- 批量插入并忽略错误
INSERT IGNORE INTO table_name (id, name) VALUES (1, 'a'), (2, 'b');
-- 批量插入并更新(UPSERT)
INSERT INTO table_name (id, name, count) VALUES (1, 'a', 10), (2, 'b', 20)
ON DUPLICATE KEY UPDATE count = VALUES(count) + count; -- VALUES() 函数引用待插入的值
-- 使用 SET 语法插入(更灵活)
INSERT INTO table_name SET id = 1, name = 'test';
3.2 查询数据 (SELECT)
sql
-- 强制使用指定索引(Index Hint)
SELECT * FROM users FORCE INDEX (idx_email) WHERE email = 'test@example.com';
SELECT * FROM users IGNORE INDEX (idx_status) WHERE status = 'active';
-- 查询锁定
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE; -- 排他锁(写锁)
SELECT * FROM orders WHERE status = 'pending' LOCK IN SHARE MODE; -- 共享锁(读锁)
-- 分组后筛选 (HAVING vs WHERE)
-- WHERE 在分组前筛选行
-- HAVING 在分组后筛选组
SELECT department, AVG(salary) as avg_sal
FROM employees
WHERE hire_date > '2020-01-01' -- 先筛选出2020年后入职的员工
GROUP BY department
HAVING AVG(salary) > 5000; -- 再筛选出平均工资大于5000的部门
-- 流程控制函数
SELECT
name,
IF(score >= 60, '及格', '不及格') AS result,
CASE
WHEN score >= 90 THEN '优秀'
WHEN score >= 80 THEN '良好'
WHEN score >= 60 THEN '及格'
ELSE '不及格'
END AS grade
FROM exam_results;
3.3 连接查询 (JOIN)
sql
-- STRAIGHT_JOIN: 强制按 FROM 子句中表的顺序进行连接
SELECT * FROM table1 STRAIGHT_JOIN table2 ON table1.id = table2.id;
3.4 子查询
sql
-- 关联子查询(效率较低,慎用)
SELECT * FROM users u WHERE (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) > 10;
-- 优化为 JOIN
SELECT u.* FROM users u JOIN (SELECT user_id, COUNT(*) as order_count FROM orders GROUP BY user_id HAVING order_count > 10) o_count ON u.id = o_count.user_id;
3.5 窗口函数 (MySQL 8.0+)
sql
-- 窗口函数框架: FUNCTION() OVER (PARTITION BY ... ORDER BY ... [frame_clause])
-- frame_clause: ROWS/RANGE BETWEEN start AND end
-- - UNBOUNDED PRECEDING: 分区开始
-- - N PRECEDING: 当前行前N行
-- - CURRENT ROW: 当前行
-- - N FOLLOWING: 当前行后N行
-- - UNBOUNDED FOLLOWING: 分区结束
-- 计算移动平均(最近3行)
SELECT
date,
amount,
AVG(amount) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3_days
FROM daily_sales;
-- 计算累计占比
SELECT
category,
amount,
SUM(amount) OVER (PARTITION BY category ORDER BY date) AS cumulative_sum,
amount / SUM(amount) OVER (PARTITION BY category) AS percentage_of_total
FROM sales;
四、索引与性能优化
4.1 索引类型
B-Tree 索引:默认索引类型,适用于全值匹配、范围查询、排序。
Hash 索引:仅 Memory 引擎显式支持,仅适用于精确匹配(=),速度快。
全文索引 (FULLTEXT) :用于 CHAR, VARCHAR, TEXT 列的文本搜索。
sql
CREATE FULLTEXT INDEX idx_content ON articles(title, body);
SELECT * FROM articles WHERE MATCH(title, body) AGAINST('MySQL 性能优化' IN NATURAL LANGUAGE MODE);
空间索引 (SPATIAL):用于地理空间数据类型。
降序索引 (Descending Index) :MySQL 8.0+ 支持,优化 ORDER BY col DESC 查询。
sql
CREATE INDEX idx_created_at_desc ON logs(created_at DESC);
隐藏索引 (Invisible Index):MySQL 8.0+ 支持,优化器会忽略此索引,用于测试删除索引的影响。
sql
CREATE INDEX idx_name ON users(name) INVISIBLE;
ALTER TABLE users ALTER INDEX idx_name VISIBLE;
函数索引 (Function-Based Index):MySQL 8.0+ 支持,对表达式结果建索引。
sql
CREATE INDEX idx_lower_email ON users((LOWER(email)));
SELECT * FROM users WHERE LOWER(email) = 'test@example.com';
4.2 性能优化建议
sql
-- 1. 使用 EXPLAIN 分析查询计划
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
EXPLAIN FORMAT=JSON SELECT ...; -- 更详细的JSON格式输出
EXPLAIN ANALYZE SELECT ...; -- MySQL 8.0+ 实际执行查询并显示成本和时间
-- 2. 避免 SELECT *,只取需要的列
SELECT id, name FROM users;
-- 3. 避免在 WHERE 子句中对索引列使用函数或计算
-- 错误: WHERE YEAR(created_at) = 2023 (索引失效)
-- 正确: WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01' (索引有效)
-- 4. 使用 EXISTS 代替 IN (对于大子查询)
-- WHERE id IN (SELECT user_id FROM orders)
-- 优化为:
-- WHERE EXISTS (SELECT 1 FROM orders WHERE user_id = users.id)
-- 5. 合理使用索引覆盖 (Covering Index)
-- 索引包含查询所需的所有列,无需回表
CREATE INDEX idx_covering ON orders (user_id, amount, status);
SELECT user_id, amount FROM orders WHERE user_id = 123; -- 只需扫描索引
-- 6. 分批处理大量数据更新/删除
-- DELETE FROM logs WHERE created_at < '2024-01-01' LIMIT 10000;
-- 在循环中执行,避免长事务和锁竞争
-- 7. 使用合适的 JOIN 算法
-- Block Nested-Loop (BNL) Join: 驱动表结果集存入 join buffer
-- MySQL 会自动选择,可通过 `optimizer_switch` 调整
-- 8. 优化 COUNT(*) 查询
-- InnoDB 中 COUNT(*) 需要全表扫描,可近似查询或使用缓存/触发器维护计数
SELECT COUNT(*) FROM users; -- 慢
SELECT TABLE_ROWS FROM information_schema.tables WHERE table_name = 'users'; -- 快但不精确
五、高级对象
5.1 视图 (VIEW)
sql
-- 创建视图
CREATE VIEW active_users_view AS
SELECT id, username, email FROM users WHERE status = 'active';
-- 可更新视图(需满足一定条件,如不含聚合、DISTINCT、GROUP BY等)
CREATE VIEW user_email_view AS SELECT id, email FROM users;
UPDATE user_email_view SET email = 'new@example.com' WHERE id = 1; -- 会更新基表
-- 查看视图定义
SHOW CREATE VIEW view_name;
5.2 存储过程与函数
sql
-- 存储过程:可以执行复杂的逻辑,无返回值(通过OUT参数返回)
DELIMITER //
CREATE PROCEDURE GetUserOrders(IN userId INT, OUT orderCount INT)
BEGIN
SELECT COUNT(*) INTO orderCount FROM orders WHERE user_id = userId;
END //
DELIMITER ;
-- 函数:必须有返回值,不能修改数据库状态(除非是 DETERMINISTIC 或 NOT DETERMINISTIC)
DELIMITER //
CREATE FUNCTION CalculateDiscount(price DECIMAL(10,2), level INT)
RETURNS DECIMAL(10,2)
DETERMINISTIC -- 声明为确定性函数,可被优化
BEGIN
DECLARE discount DECIMAL(10,2);
IF level > 3 THEN
SET discount = 0.2;
ELSEIF level > 1 THEN
SET discount = 0.1;
ELSE
SET discount = 0;
END IF;
RETURN price * (1 - discount);
END //
DELIMITER ;
5.3 触发器 (TRIGGER)
sql
-- 创建触发器
-- NEW 和 OLD 是伪记录,分别代表新/旧行数据
CREATE TRIGGER before_user_update
BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
IF OLD.email != NEW.email THEN
INSERT INTO user_audit_log (user_id, old_email, new_email, change_time)
VALUES (OLD.id, OLD.email, NEW.email, NOW());
END IF;
END;
-- 查看触发器
SHOW TRIGGERS;
SHOW TRIGGERS LIKE 'user%';
5.4 事件调度器 (Event Scheduler)
sql
-- 开启事件调度器
SET GLOBAL event_scheduler = ON;
-- 创建定时任务(例如:每天凌晨1点归档日志)
CREATE EVENT archive_logs_daily
ON SCHEDULE EVERY 1 DAY
STARTS '2024-01-01 01:00:00'
DO
BEGIN
INSERT INTO logs_archive SELECT * FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
END;
-- 查看事件
SHOW EVENTS;
-- 修改/删除事件
ALTER EVENT archive_logs_daily DISABLE; -- 禁用
DROP EVENT archive_logs_daily;
六、事务与锁
6.1 事务控制
sql
-- 事务特性 (ACID)
-- Atomicity (原子性), Consistency (一致性), Isolation (隔离性), Durability (持久性)
-- 隔离级别
-- READ UNCOMMITTED (读未提交): 脏读
-- READ COMMITTED (读已提交): 不可重复读 (Oracle, SQL Server 默认)
-- REPEATABLE READ (可重复读): 幻读 (MySQL InnoDB 默认)
-- SERIALIZABLE (串行化): 性能最差,最安全
-- 设置事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 事务操作
START TRANSACTION; -- 或 BEGIN
-- ... SQL 语句 ...
COMMIT; -- 提交
-- ROLLBACK; -- 回滚
-- 保存点 (Savepoint)
SAVEPOINT sp1;
-- ... SQL 语句 ...
ROLLBACK TO SAVEPOINT sp1; -- 回滚到保存点
RELEASE SAVEPOINT sp1; -- 释放保存点
6.2 锁机制
表锁 (Table Lock):开销小,加锁快,无死锁,但并发度低。MyISAM 默认。
sql
LOCK TABLES table_name READ; -- 共享锁
LOCK TABLES table_name WRITE; -- 排他锁
UNLOCK TABLES;
行锁 (Row Lock):开销大,加锁慢,会出现死锁,但并发度高。InnoDB 支持。
记录锁 (Record Lock):锁住单条索引记录。
间隙锁 (Gap Lock):锁住索引区间,防止幻读。
临键锁 (Next-Key Lock):记录锁 + 间隙锁。
行锁是在需要时自动加的,也可以手动控制:
sql
SELECT * FROM table_name WHERE id = 1 FOR UPDATE; -- 排他行锁
SELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE; -- 共享行锁
死锁 (Deadlock):两个或多个事务相互等待对方释放锁。InnoDB 有死锁检测机制,会自动回滚代价较小的事务。
七、用户、权限与安全
sql
-- 创建用户
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'StrongPassword123!';
CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'password';
-- 授予权限
-- 权限级别: *.* (所有库所有表), db_name.* (指定库所有表), db_name.table_name (指定表)
GRANT SELECT, INSERT ON my_app.* TO 'app_user'@'192.168.1.%';
GRANT SELECT ON my_app.products TO 'readonly_user'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION; -- 允许授权给他人
-- 撤销权限
REVOKE INSERT ON my_app.* FROM 'app_user'@'192.168.1.%';
-- 查看权限
SHOW GRANTS FOR 'app_user'@'192.168.1.%';
SHOW GRANTS FOR CURRENT_USER;
-- 刷新权限(修改授权表后需要)
FLUSH PRIVILEGES;
-- 删除用户
DROP USER 'app_user'@'192.168.1.%';
八、备份、恢复与复制
8.1 备份与恢复
sql
# 逻辑备份 (mysqldump)
# 备份整个数据库
mysqldump -u root -p --single-transaction --routines --triggers --events my_app > my_app_backup.sql
# 备份指定表
mysqldump -u root -p my_app users orders > users_orders_backup.sql
# 恢复
mysql -u root -p my_app < my_app_backup.sql
# 或在 mysql 命令行中
SOURCE /path/to/my_app_backup.sql;
--single-transaction: 对于 InnoDB 表,可以在不锁表的情况下进行一致性备份。
--routines, --triggers, --events: 备份存储过程、触发器和事件。
8.2 二进制日志 (Binary Log)
记录所有对数据库的更改(DDL 和 DML),用于主从复制和数据恢复。
在 my.cnf 或 my.ini 中配置:
sql
ini
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW # ROW, STATEMENT, MIXED
查看二进制日志:
sql
SHOW BINARY LOGS;
SHOW BINLOG EVENTS IN 'mysql-bin.000003';
使用 mysqlbinlog 工具恢复数据:
sql
bash
mysqlbinlog /var/log/mysql/mysql-bin.000003 | mysql -u root -p
九、JSON 操作 (MySQL 5.7+)
sql
-- 创建表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
info JSON
);
-- 插入 JSON
INSERT INTO products (info) VALUES
('{"name": "Laptop", "price": 1200, "specs": {"ram": "16GB", "storage": "512GB SSD"}, "tags": ["electronics", "computer"]}'),
('{"name": "Mouse", "price": 25}');
-- 查询 JSON (-> 提取, ->> 提取并去引号)
SELECT
info->'$.name' AS name_json, -- "Laptop"
info->>'$.name' AS name_string, -- Laptop
info->>'$.specs.ram' AS ram, -- 16GB
JSON_EXTRACT(info, '$.price') AS price
FROM products;
-- 更新 JSON
UPDATE products SET info = JSON_SET(info, '$.price', 1150) WHERE id = 1;
UPDATE products SET info = JSON_INSERT(info, '$.discount', 0.1) WHERE id = 1;
UPDATE products SET info = JSON_REMOVE(info, '$.specs.storage') WHERE id = 1;
UPDATE products SET info = JSON_ARRAY_APPEND(info, '$.tags', 'gadget') WHERE id = 1;
-- 查询 JSON 数组
SELECT info->'$.tags[0]' FROM products WHERE id = 1; -- "electronics"
SELECT JSON_CONTAINS(info->'$.tags', '"computer"') FROM products; -- 1 (true)
SELECT JSON_SEARCH(info, 'one', 'Mouse') FROM products; -- "$.name"
十、常用系统命令与工具
sql
-- 查看服务器状态
SHOW STATUS LIKE 'Threads_connected'; -- 当前连接数
SHOW STATUS LIKE 'Innodb_row_lock_waits'; -- InnoDB 行锁等待次数
SHOW VARIABLES LIKE 'max_connections'; -- 最大连接数
-- 查看进程列表
SHOW PROCESSLIST;
KILL [process_id]; -- 终止某个连接
-- 查看表状态
SHOW TABLE STATUS FROM database_name LIKE 'table_name';
-- 分析表
ANALYZE TABLE table_name; -- 更新索引的基数信息
OPTIMIZE TABLE table_name; -- 整理碎片(仅对MyISAM和InnoDB有效)
-- 检查表
CHECK TABLE table_name;
-- 查看字符集和排序规则
SHOW CHARACTER SET;
SHOW COLLATION;