1. SQL(结构化查询语言)
定义:用于管理和操作关系型数据库(如 MySQL、PostgreSQL、SQLite)的标准语言。
主要分类:
| 分类 | 英文全称 | 作用 | 示例 |
|---|---|---|---|
| DDL | Data Definition Language | 定义数据库结构(表、索引、视图) | CREATE TABLE, ALTER TABLE, DROP TABLE |
| DML | Data Manipulation Language | 操作数据(增、删、改) | INSERT, UPDATE, DELETE |
| DQL | Data Query Language | 查询数据 | SELECT |
| DCL | Data Control Language | 权限控制 | GRANT, REVOKE |
核心查询示例:
-- 查询年龄大于 18 岁的用户,按创建时间倒序,只取前 10 条
SELECT id, name, age
FROM users
WHERE age > 18
ORDER BY created_at DESC
LIMIT 10;
为什么重要:
- SQL 是所有关系型数据库的通用语言。
- 即使使用 ORM,理解 SQL 才能排查性能问题、编写复杂查询。
2. 索引
定义:一种用于加速数据检索的数据库结构(类似书的目录)。通常基于 B+ 树或哈希表实现。
工作原理:
- 在表的某列(或多列)上创建索引,数据库会维护一个有序的数据结构。
- 查询时,通过索引快速定位到数据行,避免全表扫描(时间复杂度从 O(n) 降到 O(log n))。
类型:
- 主键索引(Primary Key):唯一且非空,一张表只能有一个。
- 唯一索引(Unique):列值必须唯一,允许一个 NULL。
- 普通索引(Index):只加速查询,无唯一约束。
- 复合索引(Composite Index):多列组合索引,遵循最左前缀原则。
- 全文索引(Fulltext):用于文本搜索(如 MATCH AGAINST)。
代价:
- 占用额外存储空间。
- 增、删、改操作会同步更新索引,降低写入性能。
何时使用索引:
- 频繁作为查询条件的列(WHERE, JOIN, ORDER BY, GROUP BY)。
- 区分度高的列(如用户 ID、邮箱),不适合区分度低的列(如性别)。
示例:
-- 创建索引
CREATE INDEX idx_user_age ON users(age);
-- 现在执行 SELECT * FROM users WHERE age = 25; 会使用索引
慢查询排查:通过 EXPLAIN 分析是否使用了索引。
3. 事务
定义:一组数据库操作(SQL 语句)被当作一个不可分割的原子单元。要么全部成功,要么全部失败(回滚)。
经典场景:银行转账(A 扣钱、B 加钱,必须同时成功或同时失败)。
ACID 特性
| 特性 | 含义 | 说明 |
|---|---|---|
| 原子性(Atomicity) | 事务中的所有操作要么全部完成,要么全部不执行 | 通过回滚日志(undo log)实现 |
| 一致性(Consistency) | 事务执行前后,数据库从一个一致状态变到另一个一致状态 | 由应用层约束 + 数据库约束(外键、唯一)共同保证 |
| 隔离性(Isolation) | 多个并发事务互不干扰 | 通过锁机制或 MVCC(多版本并发控制)实现 |
| 持久性(Durability) | 事务一旦提交,数据永久保存(即使系统崩溃) | 通过重做日志(redo log)实现 |
隔离级别(从低到高,并发性能下降)
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| Read Uncommitted | ✔ | ✔ | ✔ |
| Read Committed | ✘ | ✔ | ✔ |
| Repeatable Read | ✘ | ✘ | ✔(MySQL InnoDB 通过间隙锁避免) |
| Serializable | ✘ | ✘ | ✘(完全串行化) |
- 脏读:读到其他事务未提交的数据。
- 不可重复读:同一事务内两次读同一行,结果不同(因其他事务更新并提交)。
- 幻读:同一事务内两次范围查询,结果行数不同(因其他事务插入或删除)。
事务控制语句(以 MySQL 为例):
START TRANSACTION; -- 或 BEGIN
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
COMMIT; -- 提交
-- 如果出错则 ROLLBACK;
在代码中使用(伪代码):
try:
db.begin()
update_account(1, -100)
update_account(2, +100)
db.commit()
except Exception:
db.rollback()
4. ORM(对象关系映射)
定义:将关系型数据库的表结构映射为编程语言中的对象,让开发者使用面向对象的方式操作数据库,避免手写 SQL。
核心映射:
- 表 → 类(Class)
- 行 → 实例(Instance)
- 字段 → 属性(Attribute)
- 外键关联 → 对象引用(关系属性)
流行 ORM 框架:
- Python:SQLAlchemy(功能最强大)、Django ORM、Peewee
- Java:Hibernate、MyBatis
- Go:GORM
- JavaScript:Sequelize、TypeORM、Prisma
示例(使用 SQLAlchemy):
# 定义模型
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer)
# 查询:User.query.filter(User.age > 18).all()
# 对应的 SQL:SELECT * FROM users WHERE age > 18;
优点:
- 提高开发效率,避免拼接 SQL 字符串的错误。
- 自动处理 SQL 注入(通过参数化查询)。
- 数据库迁移方便(如 Alembic)。
- 跨数据库支持(换数据库只需改配置,无需改代码)。
缺点:
- 复杂查询(多表 JOIN、聚合、子查询)可能比原生 SQL 难写,且性能不如手写优化 SQL。
- 增加学习成本(需要理解 ORM 的延迟加载、N+1 问题等)。
- 过度依赖可能导致开发者不熟悉 SQL 底层。
常见问题与解决:
- N+1 查询:循环查询关联对象 → 使用 joinedload 或 selectinload 预加载。
- 性能瓶颈:对复杂报表查询,直接写原生 SQL 或使用视图。
概念关联图
SQL(基础语言)
│
├── 索引(优化 SQL 查询速度)
│
├── 事务(保证 SQL 操作的 ACID)
│
└── ORM(将 SQL 表映射为对象,自动生成 SQL)
实际工作流:
1. 设计数据库表(SQL DDL)。
2. 根据需要创建索引。
3. 在应用中通过 ORM 定义模型并操作数据。
4. 当操作需要多个步骤且保证一致性时,使用事务包裹。
5. 遇到性能问题时,查看 ORM 生成的原始 SQL 并用 EXPLAIN 分析索引使用情况。
小结
| 概念 | 一句话总结 | 关键点 |
|---|---|---|
| SQL | 操作关系数据库的标准语言 | DDL / DML / DQL,查询优化 |
| 索引 | 加速查询的数据结构 | 空间换时间,最左前缀原则 |
| 事务 | 保证一组操作原子性 | ACID,隔离级别,并发控制 |
| ORM | 用对象操作数据库的抽象层 | 提高效率,但需警惕 N+1 和复杂查询 |
评论
请登录后发表评论
暂无评论,快来发表第一条评论吧!