SQL 查询优化
SQL 查询优化是提高数据库性能的关键,涉及索引优化、查询重写等技术。
索引优化
创建索引
sql
-- 创建单列索引
CREATE INDEX idx_users_name ON users(name);
-- 创建复合索引
CREATE INDEX idx_users_name_age ON users(name, age);
-- 创建唯一索引
CREATE UNIQUE INDEX idx_users_email ON users(email);
-- 创建部分索引
CREATE INDEX idx_users_active ON users(id) WHERE status = 'active';索引使用原则
sql
-- 避免在索引列上使用函数
-- 不好的写法
SELECT * FROM users WHERE YEAR(created_at) = 2023;
-- 好的写法
SELECT * FROM users WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31';
-- 避免在索引列上进行计算
-- 不好的写法
SELECT * FROM orders WHERE total * 1.1 > 1000;
-- 好的写法
SELECT * FROM orders WHERE total > 1000 / 1.1;查询重写
避免 SELECT *
sql
-- 不好的写法
SELECT * FROM users WHERE id = 1;
-- 好的写法
SELECT id, name, email FROM users WHERE id = 1;使用 JOIN 代替子查询
sql
-- 子查询
SELECT name FROM users
WHERE id IN (SELECT user_id FROM orders WHERE total > 1000);
-- JOIN
SELECT u.name FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.total > 1000;使用 UNION ALL 代替 UNION
sql
-- UNION(会去重,性能较差)
SELECT name FROM users WHERE status = 'active'
UNION
SELECT name FROM admins WHERE status = 'active';
-- UNION ALL(不去重,性能较好)
SELECT name FROM users WHERE status = 'active'
UNION ALL
SELECT name FROM admins WHERE status = 'active';查询执行计划
查看执行计划
sql
-- MySQL
EXPLAIN SELECT * FROM users WHERE name = 'John';
-- PostgreSQL
EXPLAIN ANALYZE SELECT * FROM users WHERE name = 'John';
-- SQL Server
SET SHOWPLAN_XML ON;
SELECT * FROM users WHERE name = 'John';执行计划解读
sql
-- 常见的执行计划操作
-- ALL: 全表扫描(性能最差)
-- index: 索引扫描
-- range: 索引范围扫描
-- ref: 非唯一索引扫描
-- eq_ref: 唯一索引扫描
-- const: 常量查找(性能最好)分区表
sql
-- 创建分区表(按日期分区)
CREATE TABLE orders (
id INT,
order_date DATE,
total DECIMAL(10, 2)
)
PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024)
);缓存优化
sql
-- 启用查询缓存(MySQL)
SET query_cache_type = ON;
-- 缓存特定查询
SELECT SQL_CACHE * FROM products WHERE category = 'electronics';
-- 不缓存特定查询
SELECT SQL_NO_CACHE * FROM orders WHERE status = 'pending';分页优化
sql
-- 不好的写法(偏移量大时性能差)
SELECT * FROM orders ORDER BY id LIMIT 100000, 10;
-- 好的写法(使用索引列进行分页)
SELECT * FROM orders
WHERE id > (SELECT id FROM orders ORDER BY id LIMIT 100000, 1)
ORDER BY id LIMIT 10;注意事项
- 索引不是越多越好: 过多的索引会影响写入性能
- 定期分析表: 保持统计信息最新
- 避免隐式转换: 保持数据类型一致
- 使用连接池: 减少连接开销