网站开发与设计是什么,网站建设 费用 入哪个科目,热点新闻头条,过年做那些网站致富纸上谈兵没意思#xff0c;直接上案例。 这篇整理了十个我遇到过的SQL性能问题#xff0c;每个都是真实场景#xff0c;看看你踩过几个。案例1#xff1a;SELECT * 的代价 问题SQL#xff1a; SELECT * FROM orders WHERE user_id 123;问题#xff1a;orders表有30个字段…纸上谈兵没意思直接上案例。这篇整理了十个我遇到过的SQL性能问题每个都是真实场景看看你踩过几个。案例1SELECT * 的代价问题SQLSELECT*FROMordersWHEREuser_id123;问题orders表有30个字段但业务只需要3个字段。优化后SELECTorder_id,amount,statusFROMordersWHEREuser_id123;效果查询时间从120ms降到35ms。原因减少了数据传输量可能用上覆盖索引避免回表案例2隐式类型转换问题SQLSELECT*FROMusersWHEREphone13800138000;phone字段是varchar类型传入数字。EXPLAIN结果type: ALL全表扫描。优化后SELECT*FROMusersWHEREphone13800138000;EXPLAIN结果type: ref走索引。原因类型不匹配时MySQL会把字符串转成数字比较导致索引失效。案例3函数导致索引失效问题SQLSELECT*FROMordersWHEREDATE(create_time)2024-01-15;create_time上有索引但没用上。优化后SELECT*FROMordersWHEREcreate_time2024-01-15 00:00:00ANDcreate_time2024-01-16 00:00:00;效果从全表扫描变成范围扫描快了100倍。原因对索引列使用函数优化器无法使用索引。案例4深分页问题问题SQLSELECT*FROMordersORDERBYidLIMIT500000,20;问题要扫描50万20行然后丢掉前50万行。优化方案一用上一页的IDSELECT*FROMordersWHEREid500000ORDERBYidLIMIT20;优化方案二延迟关联SELECTo.*FROMorders oINNERJOIN(SELECTidFROMordersORDERBYidLIMIT500000,20)tONo.idt.id;子查询只查主键速度快。效果从5秒降到50毫秒。案例5OR条件优化问题SQLSELECT*FROMordersWHEREuser_id123ORorder_noABC123;user_id有索引order_no也有索引但MySQL只能用一个。优化后SELECT*FROMordersWHEREuser_id123UNIONSELECT*FROMordersWHEREorder_noABC123;效果两个查询分别走各自的索引然后合并。注意如果确定没有重复数据用UNION ALL更快。案例6EXISTS vs IN问题SQL-- 查询有订单的用户SELECT*FROMusersWHEREidIN(SELECTuser_idFROMorders);orders表很大子查询返回大量数据。优化后SELECT*FROMusers uWHEREEXISTS(SELECT1FROMorders oWHEREo.user_idu.id);什么时候用什么子查询结果集小 → 用IN子查询结果集大外层表小 → 用EXISTS现代MySQL优化器通常能自动转换但复杂SQL还是要注意案例7JOIN顺序优化问题SQLSELECT*FROMorders oLEFTJOINusers uONo.user_idu.idWHEREu.status1;orders表100万users表10万。问题大表驱动小表效率低。优化后SELECT*FROMusers uINNERJOINorders oONu.ido.user_idWHEREu.status1;小表users先过滤再关联大表orders。原则小表驱动大表把过滤条件尽量放在驱动表LEFT JOIN改成INNER JOIN如果业务允许案例8COUNT优化问题SQLSELECTCOUNT(*)FROMordersWHEREstatus1;orders表1000万status1的有800万每次统计要扫描800万行。优化方案方案一加索引CREATEINDEXidx_statusONorders(status);-- 走索引扫描但还是要扫描800万个索引项方案二汇总表-- 创建汇总表CREATETABLEorder_stats(statusINTPRIMARYKEY,cntINT,updated_atDATETIME);-- 定时任务更新或触发器UPDATEorder_statsSETcnt(SELECTCOUNT(*)FROMordersWHEREstatus1),updated_atNOW()WHEREstatus1;-- 查询直接读汇总表SELECTcntFROMorder_statsWHEREstatus1;方案三近似值-- 如果不需要精确值用EXPLAIN的rows估算EXPLAINSELECT*FROMordersWHEREstatus1;-- rows字段就是估算值案例9ORDER BY优化问题SQLSELECT*FROMordersWHEREuser_id123ORDERBYcreate_timeDESC;有idx_user_id索引但排序还是用了filesort。EXPLAINExtra: Using filesort优化后CREATEINDEXidx_user_timeONorders(user_id,create_time);EXPLAINExtra: Using index不再filesort。原因联合索引里包含了排序字段数据已经有序。案例10UPDATE优化问题SQL-- 批量更新状态UPDATEordersSETstatus2WHEREstatus1ANDcreate_time2024-01-01;符合条件的有10万条一次性更新锁表时间长。优化后分批更新-- 每次更新1000条UPDATEordersSETstatus2WHEREstatus1ANDcreate_time2024-01-01LIMIT1000;-- 循环执行直到影响行数为0或者用存储过程DELIMITER//CREATEPROCEDUREbatch_update()BEGINDECLAREaffected_rowsINTDEFAULT1;WHILEaffected_rows0DOUPDATEordersSETstatus2WHEREstatus1ANDcreate_time2024-01-01LIMIT1000;SETaffected_rowsROW_COUNT();-- 稍微等一下让其他事务有机会执行DOSLEEP(0.1);ENDWHILE;END//DELIMITER;CALLbatch_update();效果避免长时间锁表其他业务可以正常执行。优化检查清单每次写SQL前过一遍这个清单□ 是否用了SELECT *改成只查需要的列 □ 有没有隐式类型转换字符串加引号 □ 索引列上有没有函数改写成范围查询 □ 有没有深分页用ID游标或延迟关联 □ OR条件能否改成UNION □ IN子查询是否可以用EXISTS或JOIN替代 □ JOIN顺序对不对小表驱动大表 □ ORDER BY能否利用索引 □ 大批量UPDATE/DELETE是否要分批 □ 最后跑一遍EXPLAIN确认总结SQL优化说到底就几个原则减少扫描行数用好索引减少回表覆盖索引减少排序索引里包含排序字段减少锁冲突批量操作分批执行减少数据传输只查需要的列遇到慢SQL先EXPLAIN看执行计划找到问题再针对性优化。有问题评论区聊。