共计 4606 个字符,预计需要花费 12 分钟才能阅读完成。
0. 快速上手
A. 本机安装(图形界面习惯)
- Windows:安装 MySQL 8.0 + Workbench,安装时记住 root 密码。
- macOS(Homebrew):
brew install mysql
brew services start mysql
mysql -uroot
B. Docker(最干净)
docker run --name mysql8 -e MYSQL_ROOT_PASSWORD=Passw0rd! \
-p 3306:3306 -d mysql:8.0
# 进入
docker exec -it mysql8 mysql -uroot -p
1. 第一次连接与基础设置
进入 MySQL 后,先做三件小事:创建业务库、设置字符集、建立普通账号。
-- 1) 新建数据库(统一用 utf8mb4 防止中文 / 表情乱码)CREATE DATABASE shop
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_0900_ai_ci;
-- 2) 创建业务账号并授予最小权限
CREATE USER 'shop_user'@'%' IDENTIFIED BY 'Shop@123';
GRANT ALL PRIVILEGES ON shop.* TO 'shop_user'@'%';
FLUSH PRIVILEGES;
-- 3) 切换到业务库
USE shop;
2. 数据模型(最小可用电商示例)
四张表:用户、商品、订单、明细。范式友好、外键清晰。
-- 用户
CREATE TABLE users (
user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 商品
CREATE TABLE products (
product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
stock INT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- 订单(主表)CREATE TABLE orders (
order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
status ENUM('paid','canceled','refunded') NOT NULL DEFAULT 'paid',
amount DECIMAL(10,2) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_orders_user FOREIGN KEY (user_id)
REFERENCES users(user_id)
) ENGINE=InnoDB;
-- 订单明细(子表)CREATE TABLE order_items (
item_id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10,2) NOT NULL,
CONSTRAINT fk_items_order FOREIGN KEY (order_id) REFERENCES orders(order_id),
CONSTRAINT fk_items_product FOREIGN KEY (product_id) REFERENCES products(product_id)
) ENGINE=InnoDB;
插入一点练习数据:
INSERT INTO users (name,email) VALUES
('Alice','alice@example.com'),('Bob','bob@example.com'),('Carol','carol@example.com');
INSERT INTO products (title,price,stock) VALUES
('机械键盘',399.00,50),('人体工学鼠标',259.00,100),('27 寸显示器',1699.00,20);
-- 一笔订单(Alice 买了两样)INSERT INTO orders (user_id,status,amount) VALUES (1,'paid',399.00+259.00);
INSERT INTO order_items (order_id,product_id,quantity,unit_price) VALUES
(1,1,1,399.00),
(1,2,1,259.00);
3. CRUD:会查会改会删(谨慎)
-- C: 新增商品 / 用户
INSERT INTO products (title,price,stock) VALUES ('USB-C 集线器',159.00,80);
-- R: 查询(挑列 + 条件 + 排序 + 限制)SELECT product_id, title, price
FROM products
WHERE price BETWEEN 100 AND 500
ORDER BY price DESC
LIMIT 5;
-- U: 更新(只改需要的行)UPDATE products SET stock = stock - 1
WHERE product_id = 1 AND stock > 0;
-- D: 删除(务必加条件)DELETE FROM products WHERE product_id = 999; -- 示例:基本无影响
4. 聚合与分组(GROUP BY / HAVING)
-- 每位用户的订单数与总金额(仅 paid)SELECT u.user_id, u.name,
COUNT(o.order_id) AS n_orders,
SUM(o.amount) AS revenue
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.status='paid'
GROUP BY u.user_id, u.name
HAVING COALESCE(SUM(o.amount),0) >= 0
ORDER BY revenue DESC;
要点
WHERE发生在分组前,HAVING发生在分组后。- 用
COALESCE处理空值,避免 NULL 参与计算。
5. 连接(JOIN)与避免重复计数
-- 订单 + 用户(横向补充)SELECT o.order_id, u.name, o.amount, o.created_at
FROM orders o
JOIN users u ON o.user_id = u.user_id;
-- 订单 GMV = 明细数量 × 单价(先在明细汇总再回连,避免倍增)SELECT o.order_id, u.name,
SUM(oi.quantity * oi.unit_price) AS gmv
FROM orders o
JOIN users u ON o.user_id = u.user_id
JOIN order_items oi ON o.order_id = oi.order_id
GROUP BY o.order_id, u.name
ORDER BY gmv DESC;
6. 视图、约束与事务(基础三件套)
视图:把常用查询固化
CREATE OR REPLACE VIEW v_user_revenue AS
SELECT u.user_id, u.name, COALESCE(SUM(o.amount),0) AS revenue
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id AND o.status='paid'
GROUP BY u.user_id, u.name;
SELECT * FROM v_user_revenue ORDER BY revenue DESC;
事务:要么都成功,要么都回滚
START TRANSACTION;
INSERT INTO orders (user_id,status,amount) VALUES (2,'paid',1699.00);
INSERT INTO order_items (order_id,product_id,quantity,unit_price)
VALUES (LAST_INSERT_ID(),3,1,1699.00);
COMMIT; -- 出错就 ROLLBACK
约束:用数据库替你“守规则”
- 外键保证“订单一定属于存在的用户”。
CHECK (quantity> 0)防止负数。UNIQUE(email)防止重复注册。
7. 索引初识与 EXPLAIN(性能从理解开始)
建立索引(高选择性列 / 连接键 / 过滤常用列)
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at);
CREATE INDEX idx_products_title ON products(title);
查看执行计划
EXPLAIN
SELECT order_id FROM orders
WHERE user_id = 1 AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY);
关注 type(最好是 ref/range/const 而不是 ALL)、key 是否命中、rows 预估。
口诀:联合索引遵循“左前缀”。上例
user_id, created_at的索引能支持WHERE user_id = ?或WHERE user_id=? AND created_at>=?,但 不能只靠它高效支持WHERE created_at>=?。
8. 备份与恢复(最基本操作)
# 备份一个库
mysqldump -h127.0.0.1 -uroot -p --databases shop > shop.sql
# 只备份表结构(无数据)mysqldump -uroot -p shop --no-data > schema.sql
# 恢复
mysql -uroot -p < shop.sql
9. 常见坑与经验法则(入门就规避)
- 字符集:统一
utf8mb4,别用历史utf8(那是“阉割版”)。 - 金钱:用
DECIMAL(10,2),不要FLOAT/DOUBLE。 - 时间:业务推荐
DATETIME(时区独立),跨时区 / 审计再考虑TIMESTAMP。 - 自增主键:
BIGINT AUTO_INCREMENT足够耐用。 - 布尔:
TINYINT(1)+ 约束 / 约定。 - 删除数据:先
SELECT ... WHERE ...验证条件再DELETE。 - JOIN 倍增:先在明细
GROUP BY再回连,或确保连接键唯一。
10. 练习(建议动手 15–20 分钟)
- 新增两位用户、两件商品;插入 3 笔订单(含至少一笔 2 个明细)。
- 写一个查询:统计最近 30 天每位用户的
订单数、总金额、客单价(总金额 / 订单数),按总金额倒序。 - 给
orders(status, created_at)建合适索引,验证你的查询EXPLAIN不再是全表扫描。 - 用事务模拟“下单减库存”:下单成功则
products.stock减对应数量,任何一步失败整体回滚。 - 创建视图
v_daily_gmv(date, gmv):按天汇总 GMV(只统计paid)。
正文完

