数据库索引优化与Redis持久化实战指南
1. 数据库索引优化实战从B树到执行计划索引优化是数据库性能调优的核心环节也是面试中最常被深挖的技术点。以MySQL的InnoDB引擎为例其索引实现基于B树数据结构这种设计使得等值查询和范围查询都能保持O(log n)的时间复杂度。但在实际业务中仅了解数据结构远远不够。1.1 复合索引的最左匹配原则假设我们有一个用户表包含字段user_id(主键)、username、age、city现在需要频繁执行以下查询SELECT * FROM users WHERE city北京 AND age25 ORDER BY username;此时创建复合索引的正确姿势应该是ALTER TABLE users ADD INDEX idx_city_age_username (city, age, username);这个索引之所以高效是因为完全覆盖WHERE条件中的字段city和age满足ORDER BY的username字段遵循最左匹配原则查询条件从索引最左侧开始匹配常见误区将选择性高的字段放在索引最前面。实际上应该按照查询条件的出现顺序和过滤性综合考量。1.2 索引失效的典型场景即使创建了合适的索引这些情况仍会导致索引失效在索引列上使用函数WHERE YEAR(create_time)2023隐式类型转换WHERE user_id10001user_id是整型使用!或操作符使用OR连接非索引列条件使用LIKE以通配符开头WHERE username LIKE %张实测案例某用户表有200万数据对手机号字段建立索引后执行WHERE mobile LIKE 138%耗时3ms而WHERE mobile LIKE %8888耗时达到1200ms。1.3 EXPLAIN执行计划深度解读理解EXPLAIN输出是诊断查询性能的关键。重点关注以下列列名关键值含义typeconst通过主键或唯一索引查询ref普通索引查询range索引范围扫描index全索引扫描ALL全表扫描key_len数值索引使用的字节数可判断是否用到全部索引列ExtraUsing filesort需要额外排序操作Using temporary需要创建临时表一个真实的优化案例某订单查询接口响应缓慢EXPLAIN显示typeALL且Extra有Using filesort。通过添加(user_id, status)复合索引并将ORDER BY改为ORDER BY user_id, create_time查询时间从2.3秒降至23ms。2. Redis持久化机制RDB与AOF的工程实践Redis作为内存数据库持久化机制直接影响数据安全性和服务性能。面试中常被问及RDB和AOF的差异及适用场景。2.1 RDB快照的底层实现RDB通过fork子进程进行数据快照关键配置参数save 900 1 # 900秒内至少1次修改触发保存 save 300 10 # 300秒内至少10次修改触发保存 dbfilename dump.rdb stop-writes-on-bgsave-error yes技术细节fork操作使用写时复制(Copy-On-Write)技术子进程遍历所有数据库生成紧凑的二进制文件默认采用LZF压缩算法生产环境经验当数据集较大(10GB)时fork可能阻塞主线程虚拟机环境fork性能较差建议物理机部署备份时建议关闭AOF重写config set auto-aof-rewrite-percentage 02.2 AOF日志的运作机制AOF以追加方式记录写命令提供三种同步策略appendonly yes appendfsync always # 每个命令都同步最安全但性能差 appendfsync everysec # 每秒同步推荐配置 appendfsync no # 由操作系统决定AOF重写过程创建新AOF文件遍历数据库生成当前数据状态的命令将新文件原子替换旧文件性能优化技巧设置no-appendfsync-on-rewrite yes避免重写时同步阻塞AOF文件过大时手动执行BGREWRITEAOF而非等待自动触发定期检查AOF文件完整性redis-check-aof --fix2.3 混合持久化实践Redis 4.0引入的混合持久化结合了两者优点aof-use-rdb-preamble yes这种模式下AOF文件前半段是RDB格式的全量数据后半段是增量AOF日志重启时先加载RDB部分再重放AOF某电商平台实测数据纯RDB启动加载8GB数据耗时45秒纯AOF加载7GB AOF耗时6分钟混合模式加载3GB(RDB)200MB(AOF)耗时28秒3. PostgreSQL向量存储AI时代的数据处理随着AI应用普及PostgreSQL凭借其强大的扩展能力成为向量数据处理的热门选择。3.1 pgvector扩展安装与使用安装步骤# 编译安装 git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git cd pgvector make make install # 数据库内创建扩展 CREATE EXTENSION vector;创建带向量列的表CREATE TABLE items ( id bigserial PRIMARY KEY, name text, description text, embedding vector(384) # 384维向量 );3.2 向量相似度搜索pgvector支持多种距离计算方式-- 欧式距离 SELECT * FROM items ORDER BY embedding - [0.1, 0.2, ...] LIMIT 10; -- 余弦相似度 SELECT * FROM items ORDER BY embedding [0.1, 0.2, ...] LIMIT 10; -- 内积 SELECT * FROM items ORDER BY embedding # [0.1, 0.2, ...] LIMIT 10;性能优化方案创建IVFFlat索引CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists 100);调整lists参数平衡精度和速度对十亿级数据考虑使用HNSW索引3.3 实际应用案例某推荐系统实现方案使用Sentence-BERT将商品描述转换为384维向量每周全量更新向量数据用户浏览时实时计算相似商品SELECT id, name FROM items WHERE category electronics ORDER BY embedding (SELECT embedding FROM users WHERE id123) LIMIT 50;性能数据100万条向量数据无索引查询耗时1200msIVFFlat索引查询耗时23ms(召回率92%)HNSW索引查询耗时45ms(召回率98%)4. 跨数据库协同方案设计现代系统往往需要多种数据库协同工作如何设计高效的数据流转方案成为面试高频考点。4.1 MySQL到Redis的缓存策略经典缓存模式对比模式写流程读流程适用场景Cache-Aside1. 写数据库2. 删缓存1. 查缓存2. 未命中则查库3. 回填缓存通用场景Write-Through1. 写缓存2. 缓存同步写库直接读缓存写少读多Write-Behind1. 写缓存2. 异步批量写库直接读缓存高写入负载防缓存击穿方案def get_user(user_id): # 尝试获取锁 lock_key flock:{user_id} if not redis.setnx(lock_key, 1, ex10): time.sleep(0.1) return get_user(user_id) try: # 查缓存 user redis.get(fuser:{user_id}) if user: return json.loads(user) # 查数据库 user db.query(SELECT * FROM users WHERE id?, user_id) if user: redis.setex(fuser:{user_id}, 3600, json.dumps(user)) return user finally: redis.delete(lock_key)4.2 PostgreSQL与Redis的实时同步使用Debezium实现CDC同步# debezium配置示例 connector.class: io.debezium.connector.postgresql.PostgresConnector database.hostname: postgres database.port: 5432 database.user: replicator database.password: password database.dbname: mydb database.server.name: pg_server table.include.list: public.users plugin.name: pgoutput处理逻辑Debezium监控WAL日志将变更事件发送到Kafka消费者服务更新Redis4.3 异构数据库事务一致性Saga模式实现示例// 订单创建Saga public class CreateOrderSaga { SagaStart public void handle(CreateOrderCommand command) { // 1. 创建订单(MySQL) Order order orderService.create(command); // 2. 扣减库存(Redis) inventoryService.reserve(order.getItems()); // 3. 扣减积分(PostgreSQL) creditService.deduct(order.getUserId(), order.getPoints()); } SagaCompensation public void compensate(CreateOrderCommand command) { // 逆向操作 creditService.refund(command.getUserId(), command.getPoints()); inventoryService.release(command.getItems()); orderService.cancel(command.getOrderId()); } }某电商平台实测数据分布式事务成功率从98.7%提升到99.99%平均延迟从320ms降至150ms通过定时任务补偿解决0.01%的异常情况