一、索引优化策略(8条)
1. 合理设计复合索引顺序
复合索引的列顺序直接影响查询效率,遵循”最左前缀原则”设计索引。例如对于(user_id, order_date, status)索引:
-- 有效使用索引的查询SELECT * FROM ordersWHERE user_id = 100 AND order_date > '2023-01-01';-- 无法使用完整索引的查询SELECT * FROM ordersWHERE order_date > '2023-01-01' AND status = 'completed';
建议将高选择性列(区分度高)放在索引左侧,范围查询列放在右侧。
2. 避免索引失效场景
常见失效场景包括:
- 列参与运算:
WHERE YEAR(create_time) = 2023 - 隐式类型转换:
WHERE user_id = '123'(user_id为数值类型) - 使用NOT、!=、<>等否定操作符
- OR条件未全部命中索引
3. 覆盖索引优化
创建包含查询所需全部字段的复合索引,避免回表操作。例如:
-- 传统查询需要回表SELECT name, email FROM users WHERE status = 1;-- 覆盖索引优化CREATE INDEX idx_users_status_info ON users(status, name, email);
4. 索引选择性分析
通过统计信息评估索引价值:
-- MySQL示例SELECTCOUNT(DISTINCT user_id)/COUNT(*) AS selectivity,COUNT(*) AS total_rowsFROM orders;
选择性接近1的列更适合建索引,低选择性字段(如性别)单独建索引效果差。
5. 索引维护策略
定期执行ANALYZE TABLE更新统计信息,对频繁更新的表考虑:
- 碎片整理:
OPTIMIZE TABLE(MySQL) - 重建索引:
ALTER INDEX ... REBUILD(Oracle) - 监控索引使用率:
sys.dm_db_index_usage_stats(SQL Server)
6. 多列索引与函数索引
对复杂查询场景:
-- 创建函数索引(Oracle示例)CREATE INDEX idx_lower_name ON customers(LOWER(name));-- JSON字段索引(MySQL 5.7+)ALTER TABLE productsADD INDEX idx_json_price((CAST(price_info->>'$.retail' AS DECIMAL(10,2))));
7. 索引与排序优化
ORDER BY子句应与索引顺序一致:
-- 优化前(需文件排序)SELECT * FROM logs ORDER BY create_time DESC LIMIT 10;-- 优化后(使用索引排序)CREATE INDEX idx_logs_time ON logs(create_time DESC);
8. 索引合并策略
现代数据库支持索引合并(Index Merge),但单索引通常更高效。可通过EXPLAIN确认是否使用合并优化。
二、查询重构技巧(12条)
9. 避免SELECT *
明确指定所需字段,减少网络传输和内存消耗:
-- 不推荐SELECT * FROM products;-- 推荐SELECT product_id, name, price FROM products;
10. 分页查询优化
大数据量分页避免OFFSET深分页:
-- 传统方式(效率低)SELECT * FROM orders ORDER BY id LIMIT 100000, 10;-- 优化方式(使用游标)SELECT * FROM orders WHERE id > 100000 ORDER BY id LIMIT 10;
11. JOIN操作优化
- 小表驱动大表:将结果集小的表放在JOIN左侧
- 避免笛卡尔积:确保JOIN条件正确
- 合理使用STRAIGHT_JOIN强制连接顺序
12. 子查询改写
将IN子查询转为JOIN:
-- 子查询版本SELECT * FROM ordersWHERE customer_id IN (SELECT id FROM customers WHERE vip = 1);-- JOIN版本SELECT o.* FROM orders oJOIN customers c ON o.customer_id = c.idWHERE c.vip = 1;
13. 批量操作优化
使用批量INSERT替代单条插入:
-- 低效方式INSERT INTO logs VALUES(1, 'msg1');INSERT INTO logs VALUES(2, 'msg2');-- 高效方式INSERT INTO logs VALUES(1, 'msg1'), (2, 'msg2');
14. 预处理语句
对重复执行的SQL使用预处理:
// JDBC示例PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");stmt.setInt(1, userId);
15. 临时表优化
复杂查询可拆分为临时表:
-- 创建临时表存储中间结果CREATE TEMPORARY TABLE temp_results ASSELECT user_id, SUM(amount) AS totalFROM orders GROUP BY user_id;-- 基于临时表二次查询SELECT u.name, t.totalFROM temp_results tJOIN users u ON t.user_id = u.id;
16. 公共表表达式(CTE)
使用WITH子句提高可读性:
WITH user_orders AS (SELECT user_id, COUNT(*) AS order_countFROM ordersGROUP BY user_id)SELECT u.name, o.order_countFROM users uJOIN user_orders o ON u.id = o.user_id;
17. 避免隐式转换
确保比较操作的数据类型一致:
-- 错误示例(字符串与数字比较)SELECT * FROM products WHERE id = '123';-- 正确示例SELECT * FROM products WHERE id = 123;
18. 合理使用NULL处理
注意NULL在比较中的特殊行为:
-- 错误示例(无法匹配NULL)SELECT * FROM users WHERE phone_number != '123';-- 正确示例SELECT * FROM usersWHERE phone_number != '123' OR phone_number IS NULL;
19. 查询重写示例
复杂条件查询优化:
-- 原始查询SELECT * FROM ordersWHERE (status = 'completed' AND amount > 100)OR (status = 'pending' AND amount > 500);-- 优化后(减少OR条件)SELECT * FROM ordersWHERE status = 'completed' AND amount > 100UNION ALLSELECT * FROM ordersWHERE status = 'pending' AND amount > 500;
20. 参数化查询
防止SQL注入同时提升执行计划复用率:
# Python示例cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
三、执行计划分析(6条)
21. 理解执行计划关键指标
- type:访问类型(ALL < index < range < ref < eq_ref < const)
- rows:预估扫描行数
- key:实际使用的索引
- Extra:额外信息(Using filesort, Using temporary)
22. 识别全表扫描
关注type=ALL且rows值大的操作,通常需要添加合适索引。
23. 排序优化
Using filesort表示需要额外排序,可通过:
- 添加ORDER BY列的索引
- 减少SELECT字段数量
- 调整sort_buffer_size参数
24. 临时表分析
Using temporary表示创建了临时表,常见于:
- GROUP BY + ORDER BY组合
- 包含DISTINCT的复杂查询
- 多表JOIN且无合适索引
25. 执行计划缓存
数据库会缓存执行计划,但数据分布变化可能导致次优计划。可通过:
- 定期执行
ANALYZE TABLE - 使用SQL提示强制特定计划
- 考虑计划固定功能(如Oracle的SQL Profile)
26. 基准测试方法
使用真实数据集进行对比测试:
-- 测试不同索引的效果SET profiling = 1;-- 执行查询1SELECT SQL_NO_CACHE * FROM orders WHERE user_id = 100;-- 执行查询2SELECT SQL_NO_CACHE * FROM orders FORCE INDEX(idx_user_date) WHERE user_id = 100;SHOW PROFILE;
四、数据库配置优化(5条)
27. 内存参数调优
关键参数包括:
innodb_buffer_pool_size(MySQL,建议设为物理内存的50-70%)shared_buffers(PostgreSQL)PGA_AGGREGATE_TARGET(Oracle)
28. 并发控制
调整连接池参数:
max_connections(MySQL)max_active_connections(连接池配置)- 合理设置事务隔离级别
29. I/O优化
- 使用SSD存储
- 调整
innodb_io_capacity参数 - 分离数据文件和日志文件到不同磁盘
30. 日志配置
- 平衡安全性与性能:
sync_binlog(0/1/N) - 控制日志文件大小:
innodb_log_file_size - 归档策略优化
31. 统计信息更新
确保优化器有准确的数据分布信息:
-- MySQL示例ANALYZE TABLE orders;-- Oracle示例EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA','ORDERS');
五、高级优化技术(10条)
32. 读写分离
将读操作分流到从库,主库专注写操作。需考虑:
- 数据同步延迟
- 事务一致性要求
- 负载均衡策略
33. 分库分表
水平拆分策略:
- 按范围分片(如日期范围)
- 按哈希分片(如用户ID哈希)
- 目录分片(维护分片映射表)
34. 查询缓存利用
合理使用查询缓存(注意MySQL 8.0已移除):
-- 检查查询缓存状态SHOW VARIABLES LIKE 'have_query_cache';SHOW STATUS LIKE 'Qcache%';
35. 物化视图实现
对复杂聚合查询创建物化视图:
-- PostgreSQL示例CREATE MATERIALIZED VIEW mv_sales_summary ASSELECT product_id, SUM(quantity) AS total_quantityFROM order_itemsGROUP BY product_id;
36. 异步处理机制
将耗时查询转为异步任务:
// 伪代码示例@Asyncpublic CompletableFuture<QueryResult> executeLongQuery(String sql) {// 执行查询并返回结果}
37. 数据库中间件
使用ProxySQL等中间件实现:
- 查询路由
- 负载均衡
- 故障转移
38. 慢查询日志分析
配置慢查询日志并定期分析:
# MySQL配置示例slow_query_log = 1slow_query_threshold = 2log_queries_not_using_indexes = 1
39. 性能监控工具
使用专业工具持续监控:
- Percona PMM
- Prometheus + Grafana
- 数据库自带性能视图(如MySQL Performance Schema)
40. 版本特性利用
根据数据库版本使用新特性:
- MySQL 8.0的窗口函数
- PostgreSQL 12的分区表改进
- Oracle 19c的自动索引管理
41. 架构级优化
从系统层面考虑:
- 缓存层(Redis/Memcached)
- 消息队列解耦
- 微服务架构拆分
- 冷热数据分离
实践建议总结
- 建立性能基准:使用
EXPLAIN ANALYZE获取实际执行数据 - 渐进式优化:每次修改一个变量进行对比测试
- 监控长期效果:性能优化可能带来其他副作用
- 文档化优化过程:记录修改原因和效果
- 定期回顾:随着数据增长需要重新评估优化策略
通过系统应用这些优化技术,可在不同业务场景下实现查询性能的显著提升。实际优化中需结合具体数据库类型、数据规模和业务特点进行针对性调整。