数据库MySQL:常用语法 / MySQL 核心知识技能梳理

一、数据库操作

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.cnfmy.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;

十一、欢迎交流指正

相关推荐
2401_871492852 小时前
如何在网页中实现国际象棋棋子的拖拽与格点吸附功能
jvm·数据库·python
m0_674294642 小时前
JavaScript窗口大小调整resize事件的适配方案
jvm·数据库·python
y = xⁿ2 小时前
Redis:分布式锁,Redisson以及看门狗机制解析
数据库·redis·分布式
qq_392690662 小时前
JavaScript中Symbol类型的唯一性特征与创建规范
jvm·数据库·python
gbase_lmax2 小时前
gbase8s数据库权限分类及基础使用
数据库·oracle
u0110225122 小时前
Go语言如何处理multipart_Go语言multipart表单教程【精通】
jvm·数据库·python
运气好好的2 小时前
HTML怎么创建灵感标签智能推荐_HTML输入自动联想标签【技巧】
jvm·数据库·python
qq_349317482 小时前
CSS如何实现动态间距调整_通过CSS变量控制padding与margin值
jvm·数据库·python