一、SQL 基础
1. 复杂查询
(1)连接查询(JOIN)
- 内连接(INNER JOIN):返回两表匹配的记录。
SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id = d.dept_id;
左连接(LEFT JOIN):返回左表所有记录,右表无匹配时补 NULL。
SELECT e.name, p.project_name FROM employees e LEFT JOIN projects p ON e.emp_id = p.lead_emp_id;
多表连接:
SELECT e.name, d.dept_name, p.project_name FROM employees e JOIN departments d ON e.dept_id = d.dept_id JOIN projects p ON e.emp_id = p.lead_emp_id;
2)子查询
- 标量子查询:返回单个值,用于条件判断
SELECT name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
行子查询:返回一行多列。
SELECT * FROM employees WHERE (dept_id, salary) = (SELECT dept_id, MAX(salary) FROM employees);
存在性查询(EXISTS)
SELECT dept_name FROM departments d WHERE EXISTS (SELECT 1 FROM employees e WHERE e.dept_id = d.dept_id);
(3)分组查询(GROUP BY)
- 基本分组
SELECT dept_id, COUNT(*) as emp_count FROM employees GROUP BY dept_id;
HAVING 过滤:对分组结果过滤(WHERE 用于分组前,HAVING 用于分组后)。
SELECT dept_id, AVG(salary) as avg_salary FROM employees GROUP BY dept_id HAVING AVG(salary) > 10000;
2. 索引优化
- 索引类型:
- B-Tree 索引:最常用,适用于等值查询和范围查询(如
WHERE age > 20
)。- 哈希索引:仅支持等值查询(如
WHERE id = 1
),不支持范围查询。- 全文索引:用于文本搜索(如
MATCH AGAINST
)。- 优化原则:
- 最左前缀匹配:复合索引(如
(a, b, c)
)支持WHERE a=1
、WHERE a=1 AND b=2
,但不支持WHERE b=2
。- 避免索引失效:避免在索引列上使用函数(如
WHERE YEAR(create_time) = 2023
)。- 覆盖索引:查询的字段直接在索引中,无需回表(如
SELECT id, name FROM users WHERE id = 1
)。- 索引失效场景:
-- 错误:索引列参与计算 SELECT * FROM orders WHERE price * 0.9 < 100; -- 正确:移项到右侧 SELECT * FROM orders WHERE price < 100 / 0.9;
二、数据库设计
1. 范式(Normalization)
- 第一范式(1NF):字段不可再分。
- 反例:
address
字段存储"北京市海淀区"
(应拆分为city
和district
)。- 第二范式(2NF):消除部分依赖(主键为复合键时)。
- 表
(订单ID, 商品ID, 商品名称, 数量)
中,商品名称
只依赖于商品ID
,应拆分表。- 第三范式(3NF):消除传递依赖。
- 表
(员工ID, 部门ID, 部门地址)
中,部门地址
通过部门ID
传递依赖,应拆分表。
2. 反范式(Denormalization)
- 定义:为提高查询性能,有意违反范式,引入冗余数据。
- 场景:
- 频繁关联的字段(如订单表冗余用户姓名,避免每次 JOIN 用户表)。
- 统计数据(如文章表保存
comment_count
字段,避免每次 COUNT 评论表)。- 优缺点:
- 优点:减少 JOIN,提升查询速度。
- 缺点:数据冗余,更新时需维护一致性(如用触发器或事务)
3. 事务隔离级别
- 四大特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
- 隔离级别:
隔离级别 脏读 不可重复读 幻读 实现方式 读未提交(Read Uncommitted) ✅ ✅ ✅ 无锁 读已提交(Read Committed) ❌ ✅ ✅ 行级共享锁,读取时加锁立即释放 可重复读(REPEATABLE READ) ❌ ❌ ✅ 行级共享锁,事务结束后释放(MySQL 默认) 串行化(SERIALIZABLE) ❌ ❌ ❌ 表级共享锁,事务结束后释放 - MySQL 默认隔离级别:
REPEATABLE READ
,通过 MVCC(多版本并发控制)解决不可重复读。
三、主流数据库
1. MySQL
- 存储引擎对比:
特性 InnoDB MyISAM 事务支持 ✅ ❌ 外键支持 ✅ ❌ 锁粒度 行锁 表锁 索引与数据存储 聚簇索引(索引和数据一起存储) 非聚簇索引(索引和数据分开) 适用场景 事务性场景(如订单、支付) 只读或插入为主(如日志) - 索引优化工具:
EXPLAIN
语句:分析查询执行计划,查看是否使用索引。EXPLAIN SELECT * FROM users WHERE age > 18;
SHOW PROFILE
:查看查询各阶段耗时。
2. Redis
- 数据结构与应用场景:
- String:缓存(如
SET user:1 '{"name":"Alice"}'
)。- Hash:存储对象(如用户信息
HSET user:1 name "Alice"
)。- List:消息队列(如
LPUSH queue task1
)。- Set:去重(如点赞用户集合)。
- Sorted Set:排行榜(如
ZADD scoreboard 100 "user1"
)。- 缓存策略:
- 缓存穿透:查询不存在的数据,导致请求直达 DB。
- 解决方案:缓存空值、布隆过滤器。
- 缓存雪崩:大量缓存同时过期,导致 DB 压力骤增。
- 解决方案:随机过期时间、多级缓存。
- 缓存击穿:热点 key 过期瞬间,大量请求直达 DB。
- 解决方案:永不过期、加互斥锁。
3. MongoDB
- 适用场景:
- 灵活 schema:文档结构不固定(如用户行为日志)。
- 高并发写入:支持分片集群,写性能优异。
- 地理空间查询:内置对地理位置的索引和查询支持。
- 与关系型数据库对比:
特性 MongoDB MySQL 数据模型 文档(JSON 格式) 表结构 查询语言 类 JSON 的 BSON SQL 事务支持 4.0 + 支持多文档事务 全事务支持 水平扩展 原生支持分片集群 需要中间件(如 ShardingSphere) 适用场景 灵活、高并发写入场景 强事务一致性场景
四、综合应用示例
场景:设计一个电商订单系统,包含用户、商品、订单表。
数据库设计:
- 用户表(users)
CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
2.商品表(products):
CREATE TABLE products ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, price DECIMAL(10, 2) NOT NULL, stock INT DEFAULT 0, category_id BIGINT, INDEX idx_category (category_id) );
3.订单表(orders):
CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, total_amount DECIMAL(10, 2) NOT NULL, status TINYINT DEFAULT 0 COMMENT '0-待支付,1-已支付', create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), INDEX idx_user_status (user_id, status) );
索引优化:
- 为
orders.user_id
添加索引,加速用户订单查询。- 复合索引
(user_id, status)
支持按用户和状态过滤(如查询用户待支付订单)。
事务示例(扣库存):
BEGIN TRANSACTION; -- 检查库存 SELECT stock FROM products WHERE id = 1 FOR UPDATE; -- 行锁 -- 扣减库存(假设库存足够) UPDATE products SET stock = stock - 1 WHERE id = 1; -- 创建订单 INSERT INTO orders (user_id, total_amount, status) VALUES (1001, 99.99, 0); COMMIT;
五、总结
数据库是面试的核心考点,需掌握:
- SQL:熟练编写复杂查询,理解索引原理与优化。
- 设计:权衡范式与反范式,根据业务选择事务隔离级别。
- 主流数据库:掌握 MySQL 存储引擎差异、Redis 缓存策略、MongoDB 适用场景。