news 2026/6/6 11:04:57

【大白话说Java面试题 第96题】【Mysql篇】第26题:日常工作中你是怎么优化 SQL 的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【大白话说Java面试题 第96题】【Mysql篇】第26题:日常工作中你是怎么优化 SQL 的?

📌PDF:大白话说Java面试题 — 03-Mysql篇

第26题:日常工作中你是怎么优化 SQL 的

📚回答:

  • 核心考点
    大厂面试要求系统性地阐述SQL优化的完整流程(发现问题→分析原因→制定方案→验证效果),掌握常用优化手段,并能结合实际案例说明。面试官常追问:“慢查询怎么定位?”、“EXPLAIN主要看哪些字段?”、“索引建了为什么查询还是慢?”

1. SQL优化完整流程

核心方法论:定位 → 分析 → 优化 → 验证

慢查询日志/业务反馈 → EXPLAIN分析执行计划 → 定位瓶颈 → 制定优化方案 → 上线验证 → 持续监控
2. 第一步:定位慢查询

2.1 开启慢查询日志

-- 查看慢查询配置SHOWVARIABLESLIKE'slow_query_log%';SHOWVARIABLESLIKE'long_query_time';-- 开启慢查询日志(生产环境需谨慎)SETGLOBALslow_query_log=ON;SETGLOBALlong_query_time=1;-- 超过1秒记录SETGLOBALlog_queries_not_using_indexes=ON;-- 记录未走索引的查询-- 慢查询日志文件位置SHOWVARIABLESLIKE'slow_query_log_file';

2.2 分析慢查询日志

# 使用mysqldumpslow工具分析mysqldumpslow-st-t10/var/lib/mysql/slow.log# 输出:按查询时间排序,取前10条最慢的SQL

2.3 性能监控指标

指标命令说明
慢查询数量SHOW STATUS LIKE 'Slow_queries'累计慢查询数
查询缓存命中率SHOW STATUS LIKE 'Qcache%'缓存命中率低需优化
临时表使用SHOW STATUS LIKE 'Created_tmp%'大量临时表需优化
索引使用情况SHOW STATUS LIKE 'Handler_read%'判断索引效率
3. 第二步:EXPLAIN分析执行计划

3.1 重点关注的字段

字段说明
typeconst/ref/rangeALL/index访问类型,至少range
key使用了索引NULL实际使用的索引
rows大(接近表总行数)估算扫描行数
filtered高(>50%)低(<10%)过滤比例
ExtraUsing indexUsing filesort/Using temporary额外信息

3.2 典型问题识别

-- 问题1:全表扫描EXPLAINSELECT*FROMusersWHEREname='张三';-- type=ALL, key=NULL → 需要建索引-- 问题2:文件排序EXPLAINSELECT*FROMusersORDERBYcreate_time;-- Extra=Using filesort → 需要为create_time建索引-- 问题3:临时表EXPLAINSELECTDISTINCTageFROMusersGROUPBYage;-- Extra=Using temporary → 优化GROUP BY/DISTINCT-- 问题4:索引失效EXPLAINSELECT*FROMusersWHEREYEAR(birthday)=1990;-- type=ALL, key=NULL → 函数导致索引失效
4. 第三步:常见优化手段

4.1 索引优化(最高优先级)

优化手段示例效果
添加索引CREATE INDEX idx_name ON users(name)全表扫描→索引查找
覆盖索引CREATE INDEX idx_covering ON users(name, age)避免回表
联合索引顺序(user_id, create_time)等值在前,范围在后索引最大化利用
删除冗余索引idx_nameidx_name_age保留后者减少写开销
前缀索引CREATE INDEX idx_content ON articles(content(20))减少索引大小

实战案例

-- 原SQL:查询某用户最近10条订单SELECT*FROMordersWHEREuser_id=123ORDERBYcreate_timeDESCLIMIT10;-- 原索引:无 或 只有(user_id)-- 问题:file sort-- 优化:创建联合索引(user_id, create_time)CREATEINDEXidx_user_timeONorders(user_id,create_time);-- 效果:type=ref, Extra=Using index condition(无需filesort)

4.2 查询语句优化

优化手段低效写法高效写法提升原因
**避免SELECT ***SELECT * FROM usersSELECT id,name FROM users减少网络传输,可能用覆盖索引
深分页优化LIMIT 100000,10主键范围查询或覆盖索引+JOIN避免扫描大量无用数据
批量操作逐条INSERTINSERT INTO t VALUES (...), (...)减少网络往返
避免函数WHERE YEAR(date)=2024WHERE date BETWEEN '2024-01-01' AND '2024-12-31'索引生效
避免隐式转换WHERE phone=13800138000WHERE phone='13800138000'索引生效
用UNION ALL代替UNIONUNION(去重)UNION ALL(不去重)避免去重开销
用EXISTS代替IN(子查询数据量大时)WHERE id IN (SELECT ...)WHERE EXISTS (SELECT 1 ...)减少结果集

深分页优化详解

-- 低效:扫描100010行,丢弃100000行SELECT*FROMordersORDERBYidLIMIT100000,10;-- 方案1:主键范围查询(id连续)SELECT*FROMordersWHEREid>100000ORDERBYidLIMIT10;-- 方案2:覆盖索引+JOIN(通用)SELECTo.*FROMorders oINNERJOIN(SELECTidFROMordersORDERBYidLIMIT100000,10)tmpONo.id=tmp.id;

4.3 表结构优化

优化手段说明示例
拆分大字段将不常查询的TEXT/BLOB分到扩展表用户主表+用户详情表
分区表按时间分区,便于删除和查询历史数据PARTITION BY RANGE (YEAR(create_time))
数据类型优化用INT代替VARCHAR、用NOT NULLstatus TINYINT代替status VARCHAR(20)
合理使用冗余减少JOIN查询订单表冗余商品名称

4.4 系统配置优化

参数推荐值作用
innodb_buffer_pool_size物理内存70-80%缓存数据和索引
innodb_log_file_size1-2GBRedo日志大小
innodb_flush_log_at_trx_commit1(强一致)/2(高性能)刷盘策略
max_connections500-1000最大连接数
query_cache_size0(MySQL 8.0已移除)MySQL 5.7可禁用

4.5 应用层优化

优化手段说明示例
缓存Redis缓存热点数据用户会话、商品详情
读写分离主库写,从库读报表查询走从库
异步处理消息队列削峰订单完成后发积分
连接池HikariCP/Druid减少连接创建开销
5. 实战案例分析

案例1:订单列表查询优化

原始SQL

SELECT*FROMordersWHEREuser_id=123ORDERBYcreate_timeDESCLIMIT10;

问题定位

  • 无索引,type=ALL,全表扫描100万行
  • Extra=Using filesort,需要额外排序

优化方案

-- 1. 创建联合索引CREATEINDEXidx_user_timeONorders(user_id,create_time);-- 2. 修改查询(只查必要字段)SELECTid,order_no,amount,create_timeFROMordersWHEREuser_id=123ORDERBYcreate_timeDESCLIMIT10;

效果

  • 扫描行数:100万 → 86
  • 查询时间:1.2秒 → 0.01秒
  • Extra:Using index condition(无filesort)

案例2:报表统计优化

原始SQL

SELECTDATE(create_time)ASdt,COUNT(*)FROMordersWHEREcreate_timeBETWEEN'2024-01-01'AND'2024-12-31'GROUPBYDATE(create_time);

问题定位

  • WHERE条件没有使用索引(函数处理create_time)
  • 全表扫描

优化方案

-- 1. 改写WHERE条件,使用范围查询SELECTDATE(create_time)ASdt,COUNT(*)FROMordersWHEREcreate_time>='2024-01-01'ANDcreate_time<'2025-01-01'GROUPBYDATE(create_time);-- 2. 添加覆盖索引CREATEINDEXidx_timeONorders(create_time);-- 3. 考虑使用汇总表(每日提前统计)CREATETABLEorder_daily_stats(stat_dateDATEPRIMARYKEY,order_countINT);

效果

  • 扫描行数:500万 → 365(索引扫描)
  • 查询时间:8秒 → 0.2秒
6. 优化checklist(面试速记)
类别检查项命令/方法
慢查询是否开启慢查询日志slow_query_log=ON
执行计划type是否为ALL/indexEXPLAIN
索引是否使用覆盖索引Extra=Using index
索引是否有冗余索引pt-duplicate-key-checker
查询是否SELECT *改为具体字段
查询深分页是否优化避免大offset
查询是否使用函数/隐式转换检查WHERE条件
表结构字段类型是否合理INT vs VARCHAR
表结构是否有分区需求大表按时间分区
配置innodb_buffer_pool_size是否足够物理内存70-80%
7. 面试官追问与高分回答

Q1:索引建了,查询还是慢,可能的原因?

A

  • 索引失效:函数、隐式转换、不遵循最左前缀
  • 区分度低:优化器选择全表扫描
  • 统计信息过期:执行ANALYZE TABLE
  • 需要回表:查询列不在索引中,尝试覆盖索引
  • 数据倾斜:某个值占比过高

Q2:如何验证优化效果?

A

  1. 执行EXPLAIN对比优化前后(type、rows、Extra)
  2. 执行SHOW PROFILE查看详细耗时
  3. 压测对比QPS和RT
  4. 上线后观察慢查询日志变化

Q3:联合索引顺序怎么确定?

A

  1. 等值查询列放前面,范围查询列放后面
  2. 高区分度列放前面
  3. 频繁查询列放前面
  4. 考虑索引复用((a,b)可覆盖(a)

Q4:表数据量特别大(亿级),怎么优化?

A

  • 分区表(按时间、按哈希)
  • 分库分表(ShardingSphere、MyCAT)
  • 冷热数据分离(历史数据归档)
  • 使用列式存储(ClickHouse)做分析查询
  • 读写分离 + 缓存

Q5:优化过程中最常用的工具?

A

  • EXPLAIN:分析执行计划
  • 慢查询日志+mysqldumpslow:定位慢SQL
  • SHOW PROFILE:查看各阶段耗时
  • pt-query-digest:分析慢查询日志
  • SHOW ENGINE INNODB STATUS:查看锁信息
  • performance_schema:深度性能分析

Q6:优化SQL的原则是什么?

A

  1. 减少扫描行数(用索引、减少SELECT字段)
  2. 减少回表次数(覆盖索引)
  3. 减少排序和临时表(用索引排序)
  4. 减少网络传输(批量操作、避免SELECT *)

💡面试官想要的满分总结

"SQL优化是一个系统性工作,我的优化流程是:定位 → 分析 → 优化 → 验证

第一步:定位慢查询

  • 开启慢查询日志(long_query_time=1
  • 使用mysqldumpslowpt-query-digest分析

第二步:EXPLAIN分析执行计划

  • 重点关注:type(至少range)、key(不为NULL)、rows(小)、Extra(无filesort/temporary)
  • 识别全表扫描、索引失效、文件排序等问题

第三步:制定优化方案

  • 索引优化:添加/优化索引、覆盖索引、联合索引顺序(等值在前,范围在后)
  • 查询优化:避免SELECT *、深分页优化、批量操作、避免函数/隐式转换
  • 表结构优化:拆分大字段、分区表、合理数据类型
  • 配置优化innodb_buffer_pool_size(70-80%内存)
  • 应用层:缓存、读写分离

第四步:验证效果

  • 重新EXPLAIN对比
  • 压测验证QPS/RT
  • 上线后监控慢查询日志

一句话:SQL优化的本质是减少扫描行数减少回表次数,核心工具是EXPLAIN,核心手段是索引优化。"


觉得对您有帮助,麻烦点点关注啦,您的关注是我创作的最大动力~ 🎯

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 11:02:04

5分钟完成网易云音乐增强:BetterNCM安装器完全使用指南

5分钟完成网易云音乐增强&#xff1a;BetterNCM安装器完全使用指南 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 你是否厌倦了网易云音乐PC版单调的功能&#xff1f;是否渴望更丰富的…

作者头像 李华
网站建设 2026/6/6 11:00:16

Java开发进阶之路:掌握SpringBoot的核心技术

在当今快速发展的软件开发领域&#xff0c;Java 依然是企业级应用开发的中流砥柱。而 Spring Boot 作为 Java 生态中的明星框架&#xff0c;以其“约定优于配置”的理念和强大的自动化配置能力&#xff0c;极大地简化了 Spring 应用的初始搭建和开发过程。对于 Java 开发者而言…

作者头像 李华
网站建设 2026/6/6 10:57:54

全链路 AI 成行业主流,招聘数字化告别单点简历筛选时代

AI招聘平台是将人工智能技术深度融入招聘全流程的系统级产品&#xff0c;核心能力包括智能简历解析、AI人才筛选与匹配、自动化流程推进和招聘决策分析。2026年&#xff0c;AI招聘平台已从锦上添花进化为企业人才竞争的基础设施——据行业数据&#xff0c;采用AI招聘平台的企业…

作者头像 李华
网站建设 2026/6/6 10:57:41

利用快马AI一键生成跨平台Python软件安装脚本原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请生成一个跨平台的Python软件安装程序脚本。该脚本需要实现以下核心功能&#xff1a;首先&#xff0c;自动检测用户当前的操作系统是Windows、macOS还是Linux。其次&#xff0c;根…

作者头像 李华