MySQL篇(三):SQL优化经验全方位解析
MySQL篇(三):SQL优化经验全方位解析
一、SQL查询优化经验
(一)合理使用查询条件
- 避免
select *
实际开发中,SELECT *
会增加数据传输与解析开销。- 反例:
-- 获取用户信息时返回所有字段,包含冗余数据 SELECT * FROM users;
- 正例:
-- 只查询必要字段,减少数据量 SELECT user_id, user_name, email FROM users;
- 反例:
- 优化
where
条件- 使用合适的比较操作符:根据需求选择精准操作符,如查询年龄大于30的用户:
SELECT * FROM users WHERE age > 30;
- 避免函数操作在查询条件字段上:对字段使用函数会导致索引失效,可用范围查询替代:
-- 反例:对字段使用函数,索引失效 SELECT * FROM orders WHERE YEAR(order_date) = 2024; -- 正例:通过范围查询替代 SELECT * FROM orders WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01';
- 使用合适的比较操作符:根据需求选择精准操作符,如查询年龄大于30的用户:
(二)JOIN操作优化
- 选择合适的JOIN类型
- 明确JOIN目的:
INNER JOIN
用于获取匹配记录,LEFT JOIN
保留左表所有记录。-- INNER JOIN:获取有订单的用户 SELECT u.user_name, o.order_id FROM users u INNER JOIN orders o ON u.user_id = o.user_id; -- LEFT JOIN:获取所有用户及其订单(包括无订单用户) SELECT u.user_name, o.order_id FROM users u LEFT JOIN orders o ON u.user_id = o.user_id;
- 避免不必要的JOIN:减少JOIN表数量,降低关联复杂度。
- 明确JOIN目的:
- 确保JOIN字段有索引
对JOIN关联字段创建索引,提升效率:-- 为orders表的user_id创建索引 CREATE INDEX idx_orders_user_id ON orders (user_id);
(三)子查询与连接查询的选择
- 评估子查询和连接查询的性能
- 子查询适用场景:逻辑清晰,适合简单查询。
-- 子查询:获取订单金额高于平均金额的订单 SELECT * FROM orders WHERE order_amount > (SELECT AVG(order_amount) FROM orders);
- 连接查询适用场景:多表关联且数据量大时性能更优。
-- 连接查询:获取用户及其订单总金额 SELECT u.user_name, SUM(o.order_amount) AS total_amount FROM users u LEFT JOIN orders o ON u.user_id = o.user_id GROUP BY u.user_id;
- 子查询适用场景:逻辑清晰,适合简单查询。
二、创建表时的优化策略
(一)字段设计优化
- 选择合适的数据类型
- 数值类型:根据数据范围选择,如用户年龄用
TINYINT
:CREATE TABLE users ( user_id INT PRIMARY KEY, age TINYINT );
- 字符串类型:
VARCHAR
用于长度不确定的字符串,CHAR
用于固定长度(如MD5值):CREATE TABLE user_credentials ( md5_hash CHAR(32) );
- 数值类型:根据数据范围选择,如用户年龄用
- 避免可为空的字段
设置字段为NOT NULL
,提升处理效率:-- 反例:email字段允许为空,增加复杂度 CREATE TABLE users ( email VARCHAR(100) ); -- 正例:设置email为NOT NULL CREATE TABLE users ( email VARCHAR(100) NOT NULL );
(二)存储引擎选择
- InnoDB引擎
- 适用场景:支持事务、外键,适合OLTP场景(如电商订单系统):
CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, FOREIGN KEY (user_id) REFERENCES users(user_id) ) ENGINE = InnoDB;
- 优势:数据安全高,支持行级锁,并发性能好。
- 适用场景:支持事务、外键,适合OLTP场景(如电商订单系统):
- MyISAM引擎
- 适用场景:读多写少,对事务要求不高(如日志记录):
CREATE TABLE access_logs ( log_id INT PRIMARY KEY, access_time DATETIME ) ENGINE = MyISAM;
- 优势:查询性能高,存储结构简单。
- 适用场景:读多写少,对事务要求不高(如日志记录):
(三)表结构规范化与反规范化
- 规范化表结构
- 减少数据冗余:遵循范式设计,如用户表与订单表分离:
-- 用户表 CREATE TABLE users ( user_id INT PRIMARY KEY, user_name VARCHAR(50), email VARCHAR(100) ); -- 订单表 CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, FOREIGN KEY (user_id) REFERENCES users(user_id) );
- 优点:数据一致性高,易于维护。
- 减少数据冗余:遵循范式设计,如用户表与订单表分离:
- 反规范化处理
- 提升查询性能:适当增加冗余字段减少JOIN。如订单表添加用户姓名:
CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, user_name VARCHAR(50), -- 冗余字段 FOREIGN KEY (user_id) REFERENCES users(user_id) );
- 适用场景:读多写少,对查询性能要求高的场景。
- 提升查询性能:适当增加冗余字段减少JOIN。如订单表添加用户姓名:
三、索引使用优化经验
(一)索引创建原则
- 基于查询频率创建
对WHERE
、ORDER BY
、GROUP BY
字段创建索引:-- 为查询条件age字段创建索引 CREATE INDEX idx_age ON users (age); -- 为排序字段order_date创建索引 CREATE INDEX idx_order_date ON orders (order_date);
- 组合索引的创建
遵循最左匹配原则,如查询WHERE country = 'China' AND city = 'Beijing'
:CREATE INDEX idx_country_city ON addresses (country, city);
(二)索引优化策略
- 避免过多索引
过多索引影响写性能,定期评估并删除冗余索引:-- 删除冗余索引 DROP INDEX idx_useless ON table_name;
- 使用覆盖索引
确保索引包含查询字段,避免回表:-- 创建覆盖索引 CREATE INDEX idx_user_id_name ON users (user_id, user_name); -- 查询语句(无需回表) SELECT user_id, user_name FROM users WHERE age > 30;
四、日常SQL语句优化实践
(一)使用执行计划分析
EXPLAIN
关键字
通过EXPLAIN
分析执行计划,查看索引使用:EXPLAIN SELECT * FROM users WHERE age > 30;
- 关键列分析:
type
:连接类型,const
、eq_ref
为优,index
、ALL
需优化。key
:显示使用的索引。rows
:预估扫描行数,越小越好。
- 关键列分析:
(二)慢查询优化
- 慢查询日志分析
开启慢查询日志(配置my.cnf
):
使用[mysqld] slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 2
mysqldumpslow
或pt-query-digest
分析日志,优化慢查询。 - 重构复杂SQL
将复杂SQL分解为子查询或临时表:-- 复杂查询 SELECT * FROM a JOIN b ON a.id = b.a_id JOIN c ON b.id = c.b_id; -- 优化:使用临时表 CREATE TEMPORARY TABLE temp_b AS SELECT * FROM b; CREATE TEMPORARY TABLE temp_c AS SELECT * FROM c; SELECT * FROM a JOIN temp_b ON a.id = temp_b.a_id JOIN temp_c ON temp_b.id = temp_c.b_id;
(三)事务优化
- 控制事务范围
减少事务内操作,缩短持续时间:-- 反例:事务包含大量操作 START TRANSACTION; -- 多个查询和更新 COMMIT; -- 正例:精简事务内容 START TRANSACTION; -- 必要更新 COMMIT;
- 合理使用事务隔离级别
根据业务选隔离级别,如读已提交(READ COMMITTED
):SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; -- 事务操作 COMMIT;
通过SQL编写、建表设计、索引使用到日常维护的优化,可全面提升数据库性能。实际项目中需结合业务场景,灵活运用优化策略,不断调试以达最佳效果。