5.0 KiB
Executable File
5.0 KiB
Executable File
title, tags, created
| title | tags | created | |||||
|---|---|---|---|---|---|---|---|
| 数据库知识库 |
|
2026-04-21 |
数据库知识库
SQL 核心语句分类
DDL(数据定义)
-- 创建表
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 修改表结构
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users DROP COLUMN phone;
-- 删除表
DROP TABLE users;
DML(数据操作)
-- 插入
INSERT INTO users (username, email) VALUES ('张三', 'zhang@example.com');
-- 更新
UPDATE users SET email = 'new@example.com' WHERE username = '张三';
-- 删除
DELETE FROM users WHERE id = 1;
-- 查询
SELECT u.username, o.order_id
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
ORDER BY u.created_at DESC
LIMIT 10;
索引设计
何时创建索引
| 场景 | 建议 |
|---|---|
| 主键 | 自动创建,无需手动添加 |
| 外键 | 建议创建,加速 JOIN |
| 频繁查询的 WHERE 条件 | 必须创建 |
| 参与 ORDER BY 的列 | 考虑创建 |
| 低选择性的列(如性别) | 不建议创建 |
索引类型
-- 单列索引
CREATE INDEX idx_users_email ON users(email);
-- 复合索引(注意列顺序)
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- 唯一索引
CREATE UNIQUE INDEX idx_users_username ON users(username);
-- 表达式索引
CREATE INDEX idx_users_email_lower ON users(LOWER(email));
-- 查看索引
\d+ users
JOIN 详解
-- INNER JOIN:只保留两边都有的记录
SELECT * FROM A INNER JOIN B ON A.id = B.a_id;
-- LEFT JOIN:以 A 为准,B 没有的为 NULL
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id;
-- RIGHT JOIN:以 B 为准,A 没有的为 NULL
SELECT * FROM A RIGHT JOIN B ON A.id = B.a_id;
-- 多表 JOIN
SELECT u.name, o.total, p.product_name
FROM users u
INNER JOIN orders o ON u.id = o.user_id
INNER JOIN products p ON o.product_id = p.id;
事务与隔离级别
-- 开启事务
BEGIN;
-- 或
START TRANSACTION;
-- 提交
COMMIT;
-- 回滚
ROLLBACK;
-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
| 隔离级别 | 脏读 | 非重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 不可能 | 可能 | 可能 |
| REPEATABLE READ | 不可能 | 不可能 | 可能(MySQL不可能) |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 |
慢查询优化
-- 开启查询分析
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE user_id = 123
AND created_at > '2024-01-01';
-- 查看慢查询日志(PostgreSQL)
SHOW log_min_duration_statement;
SHOW log_min_duration_statement = 1000; -- 记录超过1秒的查询
-- 查看当前正在执行的查询
SELECT pid, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC;
数据库设计范式
| 范式 | 要求 | 示例 |
|---|---|---|
| 1NF | 原子性,每列不可再分 | 地址拆分为省/市/区 |
| 2NF | 消除部分依赖(复合主键时) | 订单明细需包含完整主键 |
| 3NF | 消除传递依赖 | 员工表不直接存部门名,而存部门ID |
PostgreSQL 常用命令
# 连接数据库
psql -U postgres -d mydb
# 常用元命令
\l -- 列出所有数据库
\d -- 列出当前库所有表
\d users -- 查看 users 表结构
\du -- 列出所有用户
\di -- 列出所有索引
\dt -- 列出所有表
# 备份与恢复
pg_dump -U postgres mydb > backup.sql
psql -U postgres mydb < backup.sql
MySQL 常用命令
# 连接数据库
mysql -u root -p mydb
# 常用命令
SHOW DATABASES;
SHOW TABLES;
DESC users;
SHOW CREATE TABLE users\G
# 备份与恢复
mysqldump -u root -p mydb > backup.sql
mysql -u root -p mydb < backup.sql
ORM 最佳实践
# SQLAlchemy 示例(Python)
from sqlalchemy import create_engine, Column, Integer, String, DateTime
from sqlalchemy.orm import declarative_base, sessionmaker
from datetime import datetime
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(100))
created_at = Column(DateTime, default=datetime.utcnow)
# 安全的参数化查询(防止 SQL 注入!)
session.query(User).filter(User.username == username) # ✅ 安全
# 不要这样做!❌
# session.execute(f"SELECT * FROM users WHERE username = '{username}'")
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 连接超时 | 防火墙/端口未开 | 检查 pg_hba.conf / mysql user 表 |
| 字符乱码 | 编码不一致 | 指定 UTF8MB4 编码连接 |
| 主从延迟 | 从机复制慢 | 读从机、写主机 |
| 死锁 | 并发更新同一行 | 调整事务顺序、使用锁 |