程序员必备的十大技能(进阶版)之高性能数据库实战(五)

简介: 教程来源 http://qcycj.cn/ 本节涵盖数据库监控诊断(慢日志配置、实时SQL与表状态分析)、NoSQL/NewSQL选型策略(缓存穿透/击穿/雪崩应对、分库分表与TiDB对比),以及千万级订单系统的实战优化路径,强调“硬件→架构→业务”逐层治理理念。

七、数据库监控与诊断

7.1 慢查询日志配置

-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过1秒记录
SET GLOBAL log_queries_not_using_indexes = ON;  -- 记录未使用索引的查询

-- 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';

-- 使用pt-query-digest分析慢查询
-- pt-query-digest /var/log/mysql/slow.log > slow_report.txt

7.2 实时监控SQL

-- 查看当前正在执行的SQL
SELECT 
    id,
    user,
    db,
    command,
    time,
    state,
    info
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;

-- 查看事务运行情况
SELECT 
    trx_id,
    trx_state,
    trx_started,
    trx_mysql_thread_id,
    TIMESTAMPDIFF(SECOND, trx_started, NOW()) as duration_sec,
    trx_query
FROM information_schema.innodb_trx
ORDER BY duration_sec DESC;

-- 查看锁等待
SELECT 
    r.trx_id waiting_trx_id,
    r.trx_mysql_thread_id waiting_thread,
    b.trx_id blocking_trx_id,
    b.trx_mysql_thread_id blocking_thread,
    TIMESTAMPDIFF(SECOND, r.trx_started, NOW()) wait_sec
FROM information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id;

7.3 表状态分析

-- 查看表大小
SELECT 
    table_schema,
    table_name,
    ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb,
    table_rows,
    ROUND(data_length / table_rows, 2) AS avg_row_size
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema')
ORDER BY size_mb DESC
LIMIT 20;

-- 查看索引使用统计
SELECT 
    index_name,
    cardinality,
    (cardinality / table_rows) * 100 AS selectivity
FROM information_schema.statistics
WHERE table_name = 'orders'
ORDER BY selectivity DESC;

八、NoSQL与NewSQL选型

8.1 何时使用NoSQL
image.png
8.2 缓存策略实战

// 缓存穿透、击穿、雪崩处理

@Component
public class CacheService {

    // 1. 缓存穿透(查询不存在的数据):布隆过滤器 + 缓存空值
    @Autowired
    private BloomFilter bloomFilter;

    public Order getOrder(Long id) {
        // 布隆过滤器过滤不存在ID
        if (!bloomFilter.mightContain(id)) {
            return null;
        }

        String cacheKey = "order:" + id;
        Order order = redisTemplate.opsForValue().get(cacheKey);
        if (order != null) {
            // 空值标记
            if (order.getId() == -1L) {
                return null;
            }
            return order;
        }

        order = orderMapper.selectById(id);
        if (order == null) {
            // 缓存空值,过期时间短(5分钟)
            redisTemplate.opsForValue().set(cacheKey, new Order(-1L), 300, TimeUnit.SECONDS);
            return null;
        }

        redisTemplate.opsForValue().set(cacheKey, order, 3600, TimeUnit.SECONDS);
        return order;
    }

    // 2. 缓存击穿(热点key过期):互斥锁
    public Order getOrderWithMutex(Long id) {
        String cacheKey = "order:" + id;
        Order order = redisTemplate.opsForValue().get(cacheKey);
        if (order != null) {
            return order;
        }

        // 尝试获取分布式锁
        String lockKey = "lock:order:" + id;
        Boolean locked = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);

        if (Boolean.TRUE.equals(locked)) {
            try {
                // 双重检查
                order = redisTemplate.opsForValue().get(cacheKey);
                if (order != null) {
                    return order;
                }
                order = orderMapper.selectById(id);
                redisTemplate.opsForValue().set(cacheKey, order, 3600, TimeUnit.SECONDS);
                return order;
            } finally {
                redisTemplate.delete(lockKey);
            }
        } else {
            // 等待其他线程加载
            Thread.sleep(50);
            return getOrderWithMutex(id);
        }
    }

    // 3. 缓存雪崩:过期时间加随机值
    public void cacheOrder(Order order) {
        String cacheKey = "order:" + order.getId();
        int baseTtl = 3600;
        int randomTtl = ThreadLocalRandom.current().nextInt(300, 600);
        redisTemplate.opsForValue().set(cacheKey, order, baseTtl + randomTtl, TimeUnit.SECONDS);
    }
}

8.3 分库分表 vs TiDB(NewSQL)
image.png

九、实战案例:千万级订单系统优化

9.1 优化前状态
数据量:订单表5000万行

QPS:峰值3000

平均响应:800ms

慢查询:每天2000+条

9.2 优化步骤

-- Step 1: 索引优化(去除冗余,添加必要)
-- 删除未使用的索引
SELECT * FROM sys.schema_unused_indexes WHERE table_name = 'orders';
DROP INDEX idx_unused ON orders;

-- 添加复合索引覆盖80%查询
CREATE INDEX idx_user_time_status ON orders(user_id, create_time, status);
CREATE INDEX idx_shop_time ON orders(shop_id, create_time);

-- Step 2: 冷热数据分离
-- 热数据(最近3个月)保留在主表
-- 冷数据(>3个月)迁移到history表
INSERT INTO orders_history SELECT * FROM orders WHERE create_time < DATE_SUB(NOW(), INTERVAL 3 MONTH);
DELETE FROM orders WHERE create_time < DATE_SUB(NOW(), INTERVAL 3 MONTH);
-- 使用分区表简化
ALTER TABLE orders PARTITION BY RANGE (TO_DAYS(create_time)) (
    PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
    PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
    ...
);

-- Step 3: 读写分离
-- 写操作主库,读操作从库
@RoutingWith(DataSourceType.SLAVE)
public List<Order> getOrdersByUser(Long userId) {
    return orderMapper.selectByUserId(userId);
}

-- Step 4: 应用层缓存
@Cacheable(value = "order", key = "#id", unless = "#result == null")
public Order getOrder(Long id) {
    return orderMapper.selectById(id);
}

-- Step 5: SQL改写
-- 原SQL(使用子查询,性能差)
SELECT * FROM orders 
WHERE user_id IN (SELECT user_id FROM users WHERE vip_level = 5)
ORDER BY create_time DESC
LIMIT 100;

-- 改写为JOIN
SELECT o.* FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE u.vip_level = 5
ORDER BY o.create_time DESC
LIMIT 100;

记住数据库优化的黄金法则:硬件解决不了的问题,架构可以;架构解决不了的问题,业务可以。 始终保持对数据的敬畏之心,每一次变更都要有回滚预案。
来源:
http://fndvx.cn/

相关文章
|
21天前
|
前端开发 机器人 API
用两行代码将 AgentRun 集成到你的应用
AgentRun支持OpenAI协议,改两行代码即可将Agent无缝接入现有应用,兼容Python/Node.js/Java等;同时提供SDK、UI嵌入、IM机器人、云事件触发五种集成方式,开箱即用全链路能力。
|
21天前
|
运维 Cloud Native 持续交付
阿里云峰会 Agent Native 基础设施专场邀您参加!
5 月 20 日杭州·西子宾馆,阿里云峰会【Agent Native 基础设施】专题论坛上,我们将围绕云原生的 Agent Infra 全栈实践,分享阿里云在一站式构建部署、多智能体治理与协作、全链路观测与持续优化、全域智能运维等方向的工程化思考和产品解决方案,助力企业打通从 Agent 开发到规模化运行的最后一公里,让智能真正成为可持续交付的生产力。
|
21天前
|
消息中间件 负载均衡 算法
程序员必备的十大技能(进阶版)之分布式核心技术(一)
教程来源 http://unbgv.cn/ 本文系统剖析分布式核心技术,涵盖CAP/BASE理论、服务治理、一致性协议、分布式事务、锁、消息中间件、负载均衡、存储及可观测性九大维度,直击微服务演进中的核心挑战与落地实践。
|
21天前
|
安全 Java C++
【Java基础】集合框架: ConcurrentHashMap核心原理:JDK1.7 vs 1.8+ 区别、线程安全实现、分段锁 vs CAS+synchronized、扩容机制
ConcurrentHashMap是Java高并发场景下线程安全的哈希表实现,JDK1.7采用Segment分段锁(16段独立加锁),JDK1.8升级为CAS+synchronized细粒度桶锁,并引入红黑树与多线程协助扩容,显著提升性能与扩展性。
|
21天前
|
存储 安全 Java
【Java基础】集合框架: HashMap核心原理:JDK1.7 vs 1.8+ 区别、数据结构、哈希函数、扩容机制、put/get全流程、红黑树转换阈值(附《思维导图》+《面试高频考点清单》)
本文系统对比JDK1.7与1.8+中HashMap的底层原理,涵盖数据结构(数组+链表→+红黑树)、哈希函数、扩容机制、插入方式及并发问题等核心差异,助你深入理解性能优化逻辑与面试高频考点。
|
21天前
|
NoSQL Java 关系型数据库
吐血整理:2026大厂后端技术岗笔面试高频100题
本文揭秘2026大厂后端面试新趋势:题库未变,但考法剧变——从死记硬背转向考察源码理解、线上排障与设计权衡三大能力。通过真实案例对比与可落地的准备方法,帮你告别无效刷题,直击面试官真实意图。
|
21天前
|
人工智能 安全 测试技术
基于Harness + Langgraph + A2A 写一个 Agent Team,实现一支硅基团队自己 写代码
基于Harness + Langgraph + A2A 写一个 Agent Team,实现一支硅基团队自己 写代码
基于Harness + Langgraph + A2A 写一个 Agent Team,实现一支硅基团队自己 写代码
|
26天前
|
程序员 定位技术 持续交付
初级程序员必备的十大技能之 Git 版本控制(六)
教程来源 http://vrhyh.cn/ 本节详解 Git 核心实践:`.gitignore` 规则编写与常用模板;Git Flow、GitHub/GitLab 三种协作工作流;规范提交信息(Conventional Commits);分支恢复、历史修改、大文件清理等高频问题解决方案;附命令速查与知识地图。
|
21天前
|
设计模式 网络协议 Java
程序员必备的十大技能(进阶版)之网络与高并发原理(一)
教程来源 http://yyvgt.cn/ 本文深度解析网络与高并发核心原理,涵盖TCP/IP协议栈、三次握手/四次挥手、滑动窗口、拥塞控制、五种I/O模型(含epoll机制)、零拷贝、Reactor/Proactor、Java NIO/Netty源码及全链路调优,助你突破性能瓶颈,成为高阶工程师。
|
21天前
|
存储 缓存 负载均衡
程序员必备的十大技能(进阶版)之分布式核心技术(五)
教程来源 http://yvyus.cn/ 本节系统讲解分布式核心能力:涵盖加权随机、最少活跃连接等负载均衡算法;Failover、Forking等容错策略;多级缓存与一致性保障;虚拟桶分片与平滑迁移;OpenTelemetry链路追踪及全链路日志透传,助力构建高可用、可观测的分布式系统。