数据库实战全手册(终极版):从基础到高阶的全场景落地指南
针对不同数据库特性和进阶需求,本次完善补充了 PostgreSQL/Oracle 专属语法、全文索引实战案例及分片扩容方案,形成覆盖主流数据库和全生命周期的实战指南。
一、多数据库索引适配方案
1.1 PostgreSQL 索引实现(含特有类型)
sql
-- 1. 主键索引(同MySQL,支持复合主键)
CREATE TABLE "user" ("id" BIGSERIAL PRIMARY KEY COMMENT '用户ID',"name" VARCHAR(50) NOT NULL,"email" VARCHAR(100) UNIQUE COMMENT '唯一索引自动创建'
);-- 2. GIN索引(PostgreSQL特有,适合数组/JSONB类型)
-- 场景:用户标签存储为数组,需频繁查询包含某标签的用户
ALTER TABLE "user" ADD COLUMN "tags" TEXT[];
CREATE INDEX "idx_user_tags_gin" ON "user" USING GIN ("tags");
-- 查询示例:查找包含"VIP"标签的用户
SELECT * FROM "user" WHERE "tags" @> ARRAY['VIP']::TEXT[];-- 3. 部分索引(只对符合条件的行创建索引,节省空间)
-- 场景:只对未删除的活跃用户创建索引
CREATE INDEX "idx_user_active" ON "user" ("name")
WHERE "is_deleted" = false;-- 4. 表达式索引(对函数结果创建索引)
-- 场景:频繁按邮箱域名查询(如@example.com)
CREATE INDEX "idx_user_email_domain" ON "user" (SPLIT_PART("email", '@', 2));
1.2 Oracle 索引实现(含分区索引)
sql
-- 1. 主键索引(支持延迟验证)
CREATE TABLE "user" ("id" NUMBER(19) NOT NULL,"name" VARCHAR2(50) NOT NULL,CONSTRAINT "pk_user_id" PRIMARY KEY ("id") DEFERRABLE INITIALLY DEFERRED
);-- 2. 分区索引(与分区表配合,Oracle高性能核心)
-- 场景:按时间分区的订单表,创建本地分区索引
CREATE TABLE "order" ("id" NUMBER(19) NOT NULL,"order_no" VARCHAR2(32),"create_time" DATE
)
PARTITION BY RANGE ("create_time") (PARTITION "p2024q1" VALUES LESS THAN (TO_DATE('2024-04-01', 'YYYY-MM-DD')),PARTITION "p2024q2" VALUES LESS THAN (TO_DATE('2024-07-01', 'YYYY-MM-DD'))
);
-- 本地分区索引(每个分区单独创建索引)
CREATE INDEX "idx_order_create_time" ON "order" ("create_time") LOCAL;-- 3. 反转键索引(解决序列值集中插入导致的索引热点)
CREATE INDEX "idx_order_id_rev" ON "order" (REVERSE("id"));
二、全文索引实战指南
2.1 MySQL 全文索引(5.7+)
sql
-- 1. 创建全文索引(支持中文需配置ngram分词器)
ALTER TABLE "article" ADD FULLTEXT INDEX "idx_article_content" ("content") WITH PARSER ngram;-- 2. 基础查询(MATCH...AGAINST)
-- 场景:搜索包含"数据库"或"索引"的文章
SELECT * FROM "article"
WHERE MATCH("content") AGAINST('数据库 索引' IN BOOLEAN MODE);-- 3. 高级查询(排除、必须包含)
-- 场景:必须包含"MySQL",排除"Oracle",可选包含"优化"
SELECT * FROM "article"
WHERE MATCH("content") AGAINST('+MySQL -Oracle 优化' IN BOOLEAN MODE);-- 4. 性能优化:联合全文索引
ALTER TABLE "article" ADD FULLTEXT INDEX "idx_article_title_content" ("title", "content");
2.2 PostgreSQL 全文搜索(内置强大功能)
sql
-- 1. 创建全文索引(自动分词)
ALTER TABLE "article" ADD COLUMN "content_fts" TSVECTOR;
-- 触发函数:自动更新全文搜索向量
CREATE OR REPLACE FUNCTION "update_article_fts"()
RETURNS TRIGGER AS $$
BEGINNEW."content_fts" = to_tsvector('pg_catalog.chinese', NEW."title" || ' ' || NEW."content");RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER "trg_article_fts"
BEFORE INSERT OR UPDATE ON "article"
FOR EACH ROW EXECUTE FUNCTION "update_article_fts"();
-- 创建GIN索引加速查询
CREATE INDEX "idx_article_fts" ON "article" USING GIN ("content_fts");-- 2. 搜索查询(支持同义词、模糊匹配)
-- 场景:搜索包含"数据库优化"相关内容
SELECT * FROM "article"
WHERE "content_fts" @@ to_tsquery('pg_catalog.chinese', '数据库 & 优化');-- 3. 排序(按匹配度)
SELECT "id", "title", ts_rank("content_fts", to_tsquery('数据库')) AS "rank"
FROM "article"
WHERE "content_fts" @@ to_tsquery('数据库')
ORDER BY "rank" DESC;
2.3 全文索引维护与优化 Checklist
操作项 | MySQL 做法 | PostgreSQL 做法 |
---|---|---|
分词器选择 | 启用 ngram 插件(中文支持) | 使用 pg_catalog.chinese 词典 |
增量更新 | 自动维护(DML 操作触发) | 通过触发器更新 TSVECTOR 字段 |
性能监控 | 查看 Slow Query 日志中的全文查询 | 使用 pg_stat_user_indexes 监控索引使用 |
大文本优化 | 拆分表存储正文 | 使用 TOAST 存储大字段,索引只建摘要 |
同义词扩展 | 需手动维护同义词表 | 创建自定义词典(Thesaurus) |
三、分片扩容全流程方案
3.1 水平分片扩容(按时间范围)
扩容场景:订单表原按季度分片,现需细化到月度
yaml
# Sharding-JDBC 扩容后配置(application.yml)
spring:shardingsphere:rules:sharding:tables:t_order:# 扩容后的数据节点:2024年Q1拆分为1-3月actual-data-nodes: ds0.t_order_${2024..2025}_${1..12}table-strategy:standard:sharding-column: create_timesharding-algorithm-name: t_order_table_inlinesharding-algorithms:t_order_table_inline:type: INLINEprops:# 扩容后算法:按年月拆分(原按季度)algorithm-expression: t_order_${create_time.year}_${create_time.month}
数据迁移脚本(保留原数据)
sql
-- 1. 创建新分片表(如2024年1月)
CREATE TABLE "t_order_2024_1" LIKE "t_order_2024_q1";-- 2. 迁移原Q1数据到新表(按月份拆分)
INSERT INTO "t_order_2024_1"
SELECT * FROM "t_order_2024_q1"
WHERE "create_time" BETWEEN '2024-01-01' AND '2024-01-31';-- 3. 迁移完成后删除原Q1表(可选)
DROP TABLE "t_order_2024_q1";
3.2 垂直分片扩容(新增字段表)
场景:用户表字段过多,拆分出用户行为表
sql
-- 1. 创建新分片表(用户行为)
CREATE TABLE "user_behavior" ("user_id" BIGINT PRIMARY KEY,"last_login_time" DATETIME,"login_count" INT DEFAULT 0,"preferences" JSON,CONSTRAINT "fk_user_behavior_id" FOREIGN KEY ("user_id") REFERENCES "user_base" ("id")
);-- 2. 迁移历史数据
INSERT INTO "user_behavior" ("user_id", "last_login_time")
SELECT "id", "last_login_time" FROM "user_base";-- 3. 删除原表冗余字段
ALTER TABLE "user_base" DROP COLUMN "last_login_time";
应用层适配(MyBatis 示例)
java
运行
// 联合查询Mapper
public interface UserMapper {@Select("SELECT b.*, bv.preferences " +"FROM user_base b " +"LEFT JOIN user_behavior bv ON b.id = bv.user_id " +"WHERE b.id = #{userId}")UserFullInfo selectFullInfo(@Param("userId") Long userId);
}
3.3 扩容注意事项
-
停机策略:
- 小表:选择业务低峰停机迁移(如凌晨 2-4 点),预估停机时间 = 数据量 / 100 万条 * 5 分钟
- 大表:采用双写策略(同时写入新旧表),校验一致后切换读流量
-
一致性保障:
- 迁移过程中开启事务,确保原子性
- 迁移后执行校验 SQL:
SELECT COUNT(*) FROM 旧表 UNION SELECT COUNT(*) FROM 新表
-
性能监控:
- 扩容后 1 小时内监控:索引使用率(需 > 80%)、联查响应时间(需 < 500ms)
- 对比扩容前后的执行计划:
EXPLAIN ANALYZE 关键查询SQL
四、常见问题扩展解决方案
4.1 跨数据库兼容问题
问题描述 | 解决方案 | 示例代码 |
---|---|---|
分页语法差异 | 使用 MyBatis 插件自动转换 | PostgreSQL: LIMIT/OFFSET → Oracle: ROWNUM |
字符串函数差异 | 封装工具类统一处理 | MySQL: SUBSTRING → Oracle: SUBSTR |
日期函数差异 | 使用标准 SQL 或 ORM 框架函数 | SELECT CURRENT_DATE 替代数据库特有函数 |
4.2 全文索引常见问题
问题现象 | 排查方法 | 解决措施 |
---|---|---|
中文搜索无结果 | 检查分词器配置 | MySQL 启用 ngram,PostgreSQL 指定中文词典 |
搜索性能差 | 查看执行计划是否使用 GIN/GiST 索引 | 添加合适的全文索引类型 |
关键词过长匹配不到 | 调整分词长度参数 | MySQL: ngram_token_size=2;PostgreSQL: 修改词典长度 |
五、工具推荐与资源
-
索引优化工具:
- Percona Toolkit(MySQL):
pt-index-usage
分析索引使用情况 - pg_stat_statements(PostgreSQL):跟踪慢查询的索引使用
- Oracle SQL Developer:自动生成索引优化建议
- Percona Toolkit(MySQL):
-
分片管理工具:
- ShardingSphere-UI:可视化分片配置与监控
- Apache DolphinScheduler:编排分片扩容任务
- MyCat Web:分库分表运维平台
-
学习资源:
- PostgreSQL 全文搜索官方文档:https://www.postgresql.org/docs/current/textsearch.html
- Oracle 分区索引最佳实践:https://docs.oracle.com/en/database/oracle/oracle-database/21/vldbg/partitioned-indexes.html
- ShardingSphere 扩容指南:https://shardingsphere.apache.org/document/current/cn/features/sharding/usage/