索引优化实战案例

引言 本文通过5个真实案例,综合运用索引优化知识,展示完整的优化过程。 案例1:订单列表查询优化 1.1 问题 -- 慢SQL SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 20; -- 执行时间:5秒 1.2 分析 EXPLAIN SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 20; 结果: type: ref key: idx_user_id rows: 50000 Extra: Using filesort ← 文件排序 问题: 扫描5万行 需要额外排序(filesort) 1.3 优化 -- 创建联合索引 CREATE INDEX idx_user_created ON orders(user_id, created_at); -- 验证 EXPLAIN SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 20; 结果: type: ref key: idx_user_created rows: 20 Extra: Using index condition ← 无filesort 1.4 效果 执行时间:5秒 → 0.01秒 性能提升:500倍 扫描行数:50000 → 20 案例2:分页查询深分页优化 2.1 问题 -- 慢SQL(翻到第5000页) SELECT * FROM products ORDER BY id LIMIT 100000, 20; -- 执行时间:8秒 2.2 分析 EXPLAIN SELECT * FROM products ORDER BY id LIMIT 100000, 20; 问题: ...

2025-11-20 · maneng

JVM线程相关参数:优化并发性能的关键配置

一、线程栈相关参数 1.1 -Xss:线程栈大小 # 默认值(不同平台不同) # Linux/macOS:1MB # Windows:根据虚拟内存 # 设置线程栈大小 -Xss512k # 设置为512KB -Xss1m # 设置为1MB(推荐) -Xss2m # 设置为2MB 作用: 控制每个线程的栈内存大小 栈用于存储局部变量、方法调用链 调优建议: // ❌ 栈太小:StackOverflowError -Xss128k // 递归深度受限 // ❌ 栈太大:可创建线程数少 -Xss10m // 内存浪费,线程数受限 // ✅ 推荐配置 -Xss1m // 平衡性能和内存 计算可创建线程数: 最大线程数 = (最大进程内存 - JVM堆内存 - JVM非堆内存) / 线程栈大小 例如: - 最大进程内存:4GB - JVM堆内存:2GB - JVM非堆内存:512MB - 线程栈大小:1MB 最大线程数 = (4GB - 2GB - 512MB) / 1MB ≈ 1536个线程 二、锁优化相关参数 2.1 偏向锁 # 启用偏向锁(JDK 8默认启用) -XX:+UseBiasedLocking # 禁用偏向锁 -XX:-UseBiasedLocking # 偏向锁延迟启动时间(默认4秒) -XX:BiasedLockingStartupDelay=0 # 立即启用 偏向锁原理: ...

2025-11-20 · maneng

线程池监控与调优:从指标监控到性能优化

一、为什么要监控线程池? 1.1 常见线程池问题 // 线程池配置不当,导致的问题: // 1. 线程数过小:任务堆积 ThreadPoolExecutor pool = new ThreadPoolExecutor( 2, 2, // ❌ 核心线程数太少 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000) ); // 结果:任务大量排队,响应慢 // 2. 队列无界:内存溢出 ThreadPoolExecutor pool = new ThreadPoolExecutor( 10, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>() // ❌ 无界队列 ); // 结果:任务无限堆积,OOM // 3. 拒绝策略不当:任务丢失 ThreadPoolExecutor pool = new ThreadPoolExecutor( 10, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new ThreadPoolExecutor.DiscardPolicy() // ❌ 静默丢弃 ); // 结果:任务丢失,业务异常 监控目的: ✅ 发现性能瓶颈 ✅ 预防资源耗尽 ✅ 优化参数配置 ✅ 及时告警 二、核心监控指标 2.1 线程池状态指标 ThreadPoolExecutor executor = new ThreadPoolExecutor( 10, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000) ); // 1. 核心线程数 int corePoolSize = executor.getCorePoolSize(); // 2. 最大线程数 int maximumPoolSize = executor.getMaximumPoolSize(); // 3. 当前线程数 int poolSize = executor.getPoolSize(); // 4. 活跃线程数(正在执行任务的线程数) int activeCount = executor.getActiveCount(); // 5. 历史最大线程数 int largestPoolSize = executor.getLargestPoolSize(); // 6. 任务总数 long taskCount = executor.getTaskCount(); // 7. 已完成任务数 long completedTaskCount = executor.getCompletedTaskCount(); // 8. 队列中任务数 int queueSize = executor.getQueue().size(); // 9. 队列剩余容量 int remainingCapacity = executor.getQueue().remainingCapacity(); System.out.println("核心线程数:" + corePoolSize); System.out.println("最大线程数:" + maximumPoolSize); System.out.println("当前线程数:" + poolSize); System.out.println("活跃线程数:" + activeCount); System.out.println("队列中任务数:" + queueSize); System.out.println("已完成任务数:" + completedTaskCount); 2.2 关键指标说明 指标 说明 正常范围 异常信号 活跃线程数/当前线程数 线程利用率 60%-80% >90%:线程不足 队列中任务数 任务积压情况 <50% >80%:任务堆积 任务完成速率 处理能力 稳定 持续下降:性能问题 拒绝任务数 容量溢出 0 >0:需要扩容 三、线程池监控实战 3.1 自定义监控线程池 public class MonitoredThreadPoolExecutor extends ThreadPoolExecutor { private final AtomicLong totalExecutionTime = new AtomicLong(0); private final AtomicLong rejectedTaskCount = new AtomicLong(0); public MonitoredThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new MonitoredRejectedExecutionHandler()); } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); // 任务执行前的逻辑 } @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); // 任务执行后的逻辑 if (t != null) { System.err.println("任务执行异常:" + t.getMessage()); } // 统计执行时间(需要在Runnable中记录) } @Override protected void terminated() { super.terminated(); System.out.println("线程池已关闭"); printStatistics(); } // 自定义拒绝策略:记录拒绝次数 private class MonitoredRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { rejectedTaskCount.incrementAndGet(); System.err.println("任务被拒绝!拒绝次数:" + rejectedTaskCount.get()); // 告警逻辑 if (rejectedTaskCount.get() % 100 == 0) { System.err.println("⚠️ 告警:已拒绝 " + rejectedTaskCount.get() + " 个任务!"); } // 降级逻辑:调用者线程执行 r.run(); } } // 打印统计信息 public void printStatistics() { System.out.println("========== 线程池统计 =========="); System.out.println("核心线程数:" + getCorePoolSize()); System.out.println("最大线程数:" + getMaximumPoolSize()); System.out.println("当前线程数:" + getPoolSize()); System.out.println("活跃线程数:" + getActiveCount()); System.out.println("历史最大线程数:" + getLargestPoolSize()); System.out.println("任务总数:" + getTaskCount()); System.out.println("已完成任务数:" + getCompletedTaskCount()); System.out.println("队列中任务数:" + getQueue().size()); System.out.println("拒绝任务数:" + rejectedTaskCount.get()); System.out.println("================================"); } } 3.2 定时监控 public class ThreadPoolMonitor { public static void startMonitoring(ThreadPoolExecutor executor) { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(() -> { System.out.println("========== 线程池监控 =========="); System.out.println("当前时间:" + LocalDateTime.now()); System.out.println("核心线程数:" + executor.getCorePoolSize()); System.out.println("最大线程数:" + executor.getMaximumPoolSize()); System.out.println("当前线程数:" + executor.getPoolSize()); System.out.println("活跃线程数:" + executor.getActiveCount()); System.out.println("队列大小:" + executor.getQueue().size()); System.out.println("已完成任务:" + executor.getCompletedTaskCount()); // 计算线程利用率 double threadUtilization = (double) executor.getActiveCount() / executor.getPoolSize() * 100; System.out.printf("线程利用率:%.2f%%\n", threadUtilization); // 计算队列使用率 BlockingQueue<Runnable> queue = executor.getQueue(); int queueCapacity = queue.size() + queue.remainingCapacity(); double queueUtilization = (double) queue.size() / queueCapacity * 100; System.out.printf("队列使用率:%.2f%%\n", queueUtilization); // 告警逻辑 if (threadUtilization > 90) { System.err.println("⚠️ 告警:线程利用率过高!"); } if (queueUtilization > 80) { System.err.println("⚠️ 告警:队列积压严重!"); } System.out.println("================================\n"); }, 0, 5, TimeUnit.SECONDS); // 每5秒监控一次 } public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 10, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100) ); // 启动监控 startMonitoring(executor); // 提交任务... } } 四、线程池参数调优 4.1 核心线程数调优 // CPU密集型任务 int cpuCount = Runtime.getRuntime().availableProcessors(); int corePoolSize = cpuCount + 1; // N + 1 // I/O密集型任务 int corePoolSize = cpuCount * 2; // 2N // 混合型任务(推荐公式) // corePoolSize = N * (1 + WT/ST) // N = CPU核心数 // WT = 等待时间(I/O时间) // ST = 计算时间(CPU时间) // 例如: // CPU核心数:8 // 等待时间:90ms(I/O) // 计算时间:10ms(CPU) // corePoolSize = 8 * (1 + 90/10) = 8 * 10 = 80 int corePoolSize = cpuCount * (1 + waitTime / computeTime); 4.2 队列选择与容量 // 1. LinkedBlockingQueue(无界队列) // 优点:无限容量 // 缺点:可能OOM // 适用:内存充足,任务数可控 BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); // 2. LinkedBlockingQueue(有界队列) // 优点:防止OOM // 缺点:任务过多会拒绝 // 适用:需要控制内存 BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1000); // 3. ArrayBlockingQueue(有界队列) // 优点:数组实现,性能好 // 缺点:容量固定 // 适用:高性能场景 BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000); // 4. SynchronousQueue(无缓冲队列) // 优点:直接交付,吞吐量高 // 缺点:无缓冲,容易拒绝 // 适用:任务执行快,maximumPoolSize大 BlockingQueue<Runnable> queue = new SynchronousQueue<>(); // 5. PriorityBlockingQueue(优先级队列) // 优点:支持优先级 // 缺点:性能开销大 // 适用:需要优先级调度 BlockingQueue<Runnable> queue = new PriorityBlockingQueue<>(); 队列容量计算: ...

2025-11-20 · maneng

RocketMQ进阶09:消息堆积处理 - 生产故障的应急方案

引言:消息堆积的危害 堆积影响: 消费延迟增加 内存占用上升 磁盘空间不足 系统性能下降 原因分析 1. Consumer消费速度慢 - 业务逻辑耗时 - 数据库慢查询 - 外部接口超时 2. Consumer数量不足 - 单个Consumer处理能力有限 3. Consumer宕机 - 无Consumer消费 解决方案 方案1:增加Consumer # 快速扩容Consumer实例 docker run -d rocketmq-consumer 方案2:提升消费性能 // 增加消费线程 consumer.setConsumeThreadMin(50); consumer.setConsumeThreadMax(100); // 批量消费 consumer.setConsumeMessageBatchMaxSize(16); // 优化业务逻辑 // - 异步处理 // - 批量操作数据库 // - 使用缓存 方案3:临时限流 // 限制Producer发送速率 Thread.sleep(10); // 每条消息延迟10ms 方案4:跳过堆积消息 // 紧急情况:重置offset跳过堆积 consumer.resetOffsetByTimestamp(topic, timestamp); 监控告警 监控指标: - 消费延迟(Consumer Lag) - 堆积消息数量 - 消费TPS 告警阈值: - 延迟 > 5分钟 - 堆积 > 10万条 本文关键词:消息堆积 故障处理 性能调优 应急方案

2025-11-14 · maneng

MySQL查询优化:从执行计划到性能调优

引言 “过早优化是万恶之源。但当性能问题真正出现时,优化就是救命稻草。” —— Donald Knuth 在前三篇文章中,我们学习了索引、事务、锁的原理。但光有理论还不够,如何定位和优化慢查询? 想象这样的场景: 凌晨3点,你被一通电话吵醒: "数据库快挂了,所有查询都超时!" 你打开监控,发现: - CPU 100% - 慢查询日志爆满 - 某个SQL执行了10秒还没返回 如何快速定位问题?如何优化这个慢查询? 这就是查询优化的核心价值:让慢查询变快,让系统起死回生。 今天,我们从第一性原理出发,深度剖析MySQL的查询优化: SQL执行流程: 客户端 → 连接器 → 解析器 → 优化器 → 执行器 → 存储引擎 ↓ ↓ ↓ ↓ ↓ 权限检查 语法解析 生成计划 执行查询 返回数据 性能优化: 慢查询 → EXPLAIN → 找到瓶颈 → 优化索引 → 改写SQL → 性能飞跃 10秒 分析 全表扫描 建索引 覆盖索引 10ms 我们还将通过10个真实案例,将慢查询从10秒优化到10ms,性能提升1000倍。 一、SQL执行流程:从SQL到结果集 理解查询优化,首先要理解SQL是如何执行的。 1.1 MySQL的架构:两层结构 ┌─────────────────────────────────────────────────────────────┐ │ MySQL Server层 │ ├─────────────────────────────────────────────────────────────┤ │ 连接器 解析器 优化器 执行器 │ │ ↓ ↓ ↓ ↓ │ │ 权限验证 语法解析 生成计划 执行查询 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 存储引擎层 │ ├─────────────────────────────────────────────────────────────┤ │ InnoDB MyISAM Memory Archive │ │ ↓ ↓ ↓ ↓ │ │ 事务支持 不支持 内存存储 压缩存储 │ └─────────────────────────────────────────────────────────────┘ Server层与存储引擎的职责分工: ...

2025-11-03 · maneng

MySQL查询优化:从执行计划到性能调优

引言 “过早优化是万恶之源。但当性能问题真正出现时,优化就是救命稻草。” —— Donald Knuth 在前三篇文章中,我们学习了索引、事务、锁的原理。但光有理论还不够,如何定位和优化慢查询? 想象这样的场景: 凌晨3点,你被一通电话吵醒: "数据库快挂了,所有查询都超时!" 你打开监控,发现: - CPU 100% - 慢查询日志爆满 - 某个SQL执行了10秒还没返回 如何快速定位问题?如何优化这个慢查询? 这就是查询优化的核心价值:让慢查询变快,让系统起死回生。 今天,我们从第一性原理出发,深度剖析MySQL的查询优化: SQL执行流程: 客户端 → 连接器 → 解析器 → 优化器 → 执行器 → 存储引擎 ↓ ↓ ↓ ↓ ↓ 权限检查 语法解析 生成计划 执行查询 返回数据 性能优化: 慢查询 → EXPLAIN → 找到瓶颈 → 优化索引 → 改写SQL → 性能飞跃 10秒 分析 全表扫描 建索引 覆盖索引 10ms 我们还将通过10个真实案例,将慢查询从10秒优化到10ms,性能提升1000倍。 一、SQL执行流程:从SQL到结果集 理解查询优化,首先要理解SQL是如何执行的。 1.1 MySQL的架构:两层结构 ┌─────────────────────────────────────────────────────────────┐ │ MySQL Server层 │ ├─────────────────────────────────────────────────────────────┤ │ 连接器 解析器 优化器 执行器 │ │ ↓ ↓ ↓ ↓ │ │ 权限验证 语法解析 生成计划 执行查询 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 存储引擎层 │ ├─────────────────────────────────────────────────────────────┤ │ InnoDB MyISAM Memory Archive │ │ ↓ ↓ ↓ ↓ │ │ 事务支持 不支持 内存存储 压缩存储 │ └─────────────────────────────────────────────────────────────┘ Server层与存储引擎的职责分工: ...

2025-11-03 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...