MySQL关键参数的最佳配置

描述

一、概述

1.1 背景介绍

运维MySQL数据库十年有余,见过太多因为参数配置不当导致的性能问题。有的公司用着默认配置跑生产环境,128GB内存的服务器上InnoDB缓冲池只有128MB;有的把max_connections设成几万,结果OOM把数据库打挂;还有的sync_binlog设成1,却抱怨写入性能差。

MySQL的可配置参数有数百个,但真正影响性能的核心参数只有二三十个。本文将基于十年运维经验,筛选出20个最关键的参数,详细讲解每个参数的作用原理、取值依据和调优方法。这些参数经过多个大型生产环境的验证,能够覆盖90%以上的调优场景。

本文的目标不是列出一堆参数让人照抄,而是让读者理解每个参数背后的原理,能够根据自己的硬件配置和业务特点,做出正确的调优决策。

1.2 技术特点

MySQL架构与参数关系

 

                          ┌─────────────────────────────────────────────┐
                          │              MySQL Server                   │
                          │  ┌─────────────────────────────────────┐   │
                          │  │         Connection Layer             │   │
                          │  │  • max_connections                   │   │
                          │  │  • thread_cache_size                 │   │
                          │  │  • wait_timeout                      │   │
                          │  └─────────────────────────────────────┘   │
                          │  ┌─────────────────────────────────────┐   │
                          │  │          SQL Layer                   │   │
                          │  │  • sort_buffer_size                  │   │
                          │  │  • join_buffer_size                  │   │
                          │  │  • tmp_table_size                    │   │
                          │  └─────────────────────────────────────┘   │
                          │  ┌─────────────────────────────────────┐   │
                          │  │        Storage Engine (InnoDB)       │   │
                          │  │  • innodb_buffer_pool_size           │   │
                          │  │  • innodb_log_file_size              │   │
                          │  │  • innodb_flush_log_at_trx_commit    │   │
                          │  │  • innodb_io_capacity                │   │
                          │  └─────────────────────────────────────┘   │
                          └─────────────────────────────────────────────┘
                                              │
                          ┌───────────────────┴───────────────────┐
                          │            Disk I/O                    │
                          │  • Data Files  • Redo Log  • Binlog   │
                          └────────────────────────────────────────┘

 

参数分类

分类 参数特点 代表参数
连接类 控制客户端连接行为 max_connections, wait_timeout
内存类 控制各类缓冲区大小 innodb_buffer_pool_size, sort_buffer_size
IO类 控制磁盘读写行为 innodb_io_capacity, sync_binlog
日志类 控制日志记录行为 innodb_log_file_size, binlog_format
复制类 控制主从复制行为 replica_parallel_workers

调优原则

理解为先:先理解参数作用,再调整数值

一次一个:每次只调整一个参数,观察效果

监控验证:调整后必须通过监控验证效果

压测确认:重大调整需在测试环境压测验证

记录变更:所有调整都要记录变更历史

1.3 适用场景

本文的调优建议适用于:

MySQL 8.0.35+ 或 8.4 LTS版本

专用数据库服务器(非混合部署)

16GB以上内存的服务器

SSD/NVMe存储环境

OLTP为主的业务场景

对于以下场景需要特别调整:

OLAP分析型场景:需要增大排序和临时表相关缓冲区

混合部署场景:需要严格限制MySQL内存使用

HDD机械硬盘:IO相关参数需要保守设置

1.4 环境要求

组件 版本要求 说明
MySQL 8.0.35+ / 8.4 LTS 推荐8.4 LTS长期支持版本
操作系统 Rocky 9 / Ubuntu 24.04 内核5.14+支持io_uring
内存 16GB+ 建议专用服务器32GB+
磁盘 NVMe SSD IOPS > 10000
CPU 8核+ 支持超线程
文件系统 XFS/ext4 推荐XFS

二、详细步骤

2.1 准备工作

2.1.1 当前配置检查

调优之前,先了解当前配置状态:

 

-- 查看关键参数当前值
SELECT
    VARIABLE_NAME,
    VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME IN (
    'innodb_buffer_pool_size',
    'innodb_buffer_pool_instances',
    'innodb_log_file_size',
    'innodb_log_buffer_size',
    'innodb_flush_log_at_trx_commit',
    'innodb_flush_method',
    'innodb_io_capacity',
    'innodb_io_capacity_max',
    'innodb_read_io_threads',
    'innodb_write_io_threads',
    'max_connections',
    'thread_cache_size',
    'table_open_cache',
    'sort_buffer_size',
    'join_buffer_size',
    'tmp_table_size',
    'max_heap_table_size',
    'sync_binlog',
    'binlog_cache_size'
)
ORDERBY VARIABLE_NAME;

 

2.1.2 硬件信息收集

 

#!/bin/bash
# collect_hardware_info.sh
# 收集服务器硬件信息

echo"=== MySQL调优信息收集 ==="

echo -e "
[CPU信息]"
lscpu | grep -E "^(CPU(s)|Thread|Core|Socket|Model name)"

echo -e "
[内存信息]"
free -h
cat /proc/meminfo | grep -E "^(MemTotal|MemFree|Cached|Buffers)"

echo -e "
[磁盘信息]"
lsblk -d -o NAME,SIZE,ROTA,TYPE,MODEL
# ROTA=0表示SSD,ROTA=1表示HDD

echo -e "
[磁盘IO能力测试]"
# 使用fio测试4K随机读写IOPS
ifcommand -v fio &> /dev/null; then
    echo"测试4K随机读IOPS..."
    fio --name=randread --ioengine=libaio --direct=1 --bs=4k 
        --iodepth=64 --rw=randread --size=1G --runtime=30 
        --time_based --filename=/tmp/fio_test 
        2>/dev/null | grep -E "(read:|IOPS)"
fi

echo -e "
[MySQL数据目录磁盘使用]"
df -h /var/lib/mysql

echo -e "
[当前MySQL进程内存使用]"
ps aux | grep mysqld | grep -v grep | awk '{print "RSS: " $6/1024 " MB"}'

 

2.1.3 性能基线记录

 

-- 记录调优前的性能基线

-- 1. InnoDB缓冲池命中率
SELECT
    (1 - (
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') /
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')
    )) * 100AS buffer_pool_hit_rate;

-- 2. 临时表使用情况
SELECT
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Created_tmp_disk_tables') /
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Created_tmp_tables') * 100
    AS tmp_disk_table_pct;

-- 3. 连接使用情况
SELECT
    @@max_connections AS max_conn,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Max_used_connections') AS max_used,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Threads_connected') AS current_conn;

-- 4. 慢查询数量
SELECT VARIABLE_VALUE AS slow_queries
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Slow_queries';

-- 5. 排序和连接相关
SELECT
    gs1.VARIABLE_VALUE AS sort_merge_passes,
    gs2.VARIABLE_VALUE AS select_full_join
FROM performance_schema.global_status gs1,
     performance_schema.global_status gs2
WHERE gs1.VARIABLE_NAME = 'Sort_merge_passes'
AND gs2.VARIABLE_NAME = 'Select_full_join';

 

2.2 核心配置

2.2.1 InnoDB核心参数(参数1-8)

参数1: innodb_buffer_pool_size

这是MySQL最重要的参数,没有之一。InnoDB缓冲池用于缓存数据页和索引页,缓冲池越大,能缓存的数据越多,磁盘IO越少,性能越好。

 

# 计算公式:物理内存 * 0.7 ~ 0.8(专用服务器)
# 示例:64GB内存服务器
innodb_buffer_pool_size = 48G

 

取值依据

内存大小 推荐值 说明
8GB 5-6GB 留2-3GB给系统和其他进程
16GB 10-12GB 约70-75%
32GB 22-25GB 约70-80%
64GB 45-50GB 约70-80%
128GB 96-100GB 约75-80%

验证效果

 

-- 查看缓冲池命中率(应 > 99%)
SHOWGLOBALSTATUSLIKE'Innodb_buffer_pool_read%';

-- 计算命中率
SELECT
    ROUND((1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100, 2) AS hit_rate
FROM (
    SELECT
        SUM(CASEWHEN VARIABLE_NAME = 'Innodb_buffer_pool_reads'THENCAST(VARIABLE_VALUE ASUNSIGNED) END) AS Innodb_buffer_pool_reads,
        SUM(CASEWHEN VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'THENCAST(VARIABLE_VALUE ASUNSIGNED) END) AS Innodb_buffer_pool_read_requests
    FROM performance_schema.global_status
    WHERE VARIABLE_NAME IN ('Innodb_buffer_pool_reads', 'Innodb_buffer_pool_read_requests')
) AS stats;

 

参数2: innodb_buffer_pool_instances

将缓冲池分成多个实例,减少多线程并发访问时的锁竞争。

 

# 当buffer_pool_size > 1GB时设置
# 建议:每个实例1-2GB,最大不超过64
innodb_buffer_pool_instances = 8

# MySQL 8.0默认已经自动设置合理值
# 当buffer_pool_size < 1GB时,自动设为1

 

参数3: innodb_log_file_size

InnoDB重做日志文件大小。更大的日志文件可以减少checkpoint频率,提高写入性能,但会增加崩溃恢复时间。

 

# MySQL 8.0.30+ 使用 innodb_redo_log_capacity 替代
# innodb_redo_log_capacity = innodb_log_file_size * innodb_log_files_in_group * 2

# MySQL 8.0.30之前的配置
innodb_log_file_size = 2G
innodb_log_files_in_group = 2

# MySQL 8.0.30+的配置
innodb_redo_log_capacity = 8G  # 相当于之前的4个2G日志文件

 

取值依据

 

-- 计算1小时内产生的日志量,以此为基准设置
SHOW ENGINE INNODB STATUSG
-- 查看 Log sequence number 和 Log flushed up to
-- 一小时前后的差值就是每小时日志量

-- 建议设置为能容纳1小时日志量的2-4倍
-- 典型值范围:1GB - 8GB

 

参数4: innodb_log_buffer_size

重做日志缓冲区大小。事务在提交前先写入日志缓冲区,然后刷盘。

 

# 默认16MB,大事务场景可适当增大
innodb_log_buffer_size = 64M

 

什么时候需要增大

 

-- 查看日志缓冲区等待次数
SHOW GLOBAL STATUS LIKE 'Innodb_log_waits';

-- 如果Innodb_log_waits > 0,说明日志缓冲区不够
-- 需要增大innodb_log_buffer_size

 

参数5: innodb_flush_log_at_trx_commit

这是性能与数据安全的平衡参数,控制redo log的刷盘策略。

 

# 取值说明:
# 0: 每秒刷盘,事务提交时不刷盘(最快,可能丢1秒数据)
# 1: 每次提交都刷盘(最安全,性能最差)
# 2: 每次提交写OS缓存,每秒刷盘(折中方案)

# 生产环境推荐
innodb_flush_log_at_trx_commit = 1  # 金融等对数据安全要求极高的场景

# 或
innodb_flush_log_at_trx_commit = 2  # 一般业务场景,OS崩溃时可能丢1秒数据

 

性能对比

取值 数据安全性 写入TPS 适用场景
0 低(可能丢1秒) 最高 测试环境
1 最高 较低 金融、订单系统
2 中(OS崩溃丢1秒) 较高 一般业务

参数6: innodb_flush_method

控制InnoDB数据文件和日志文件的刷盘方法。

 

# Linux环境推荐O_DIRECT
# 避免双重缓存(InnoDB缓冲池 + OS Page Cache)
innodb_flush_method = O_DIRECT

# MySQL 8.0默认值
# 如果使用SSD,O_DIRECT是最佳选择

 

取值说明

方法 数据文件 日志文件 适用场景
fsync 系统默认 系统默认 传统HDD
O_DIRECT 绕过OS缓存 fsync SSD,推荐
O_DIRECT_NO_FSYNC 绕过缓存,无fsync 无fsync 高性能SSD

参数7: innodb_io_capacity

告诉InnoDB后台任务可用的IOPS能力。

 

# 根据磁盘类型设置
# HDD: 200-800
# SSD: 5000-20000
# NVMe: 20000-50000

innodb_io_capacity = 10000      # 普通SSD
innodb_io_capacity_max = 20000  # 最大值

 

如何确定正确的值

 

# 1. 使用fio测试磁盘IOPS
fio --name=randrw --ioengine=libaio --direct=1 --bs=16k 
    --iodepth=64 --rw=randrw --rwmixread=70 --size=1G 
    --runtime=60 --time_based --filename=/var/lib/mysql/fio_test

# 2. 设置io_capacity为测试结果的50-75%
# 3. 设置io_capacity_max为测试结果的100%

 

参数8: innodb_read_io_threads / innodb_write_io_threads

控制InnoDB后台IO线程数量。

 

# 默认值都是4
# SSD环境可以适当增加
innodb_read_io_threads = 8
innodb_write_io_threads = 8

# 计算依据:
# 读线程:处理预读和从磁盘读取数据
# 写线程:处理脏页刷盘
# 一般设置为CPU核心数的一半

 

2.2.2 连接与线程参数(参数9-12)

参数9: max_connections

允许的最大并发连接数。

 

# 不要设置过大!每个连接都会消耗内存
# 计算公式:预期并发用户数 * 1.5

# 根据应用规模设置
max_connections = 500  # 中小型应用
# max_connections = 2000  # 大型应用

 

设置过大的危害

 

-- 每个连接的内存消耗(近似)
-- 基础消耗 + sort_buffer + join_buffer + read_buffer + ...
-- 约 2-10MB per connection

-- 假设max_connections = 10000,sort_buffer = 4MB
-- 最坏情况内存消耗:10000 * 4MB = 40GB
-- 可能导致OOM

 

合理设置

 

-- 查看历史最大连接数
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW GLOBAL STATUS LIKE 'Max_used_connections_time';

-- 建议设置为历史最大值的1.5-2倍
-- 但不要超过实际需要

 

参数10: thread_cache_size

线程缓存大小,用于复用已创建的线程。

 

# 计算公式:max_connections / 10,最大不超过100
thread_cache_size = 50

 

验证效果

 

-- 查看线程创建情况
SHOW GLOBAL STATUS LIKE 'Threads_%';

-- 线程缓存命中率计算
-- 命中率 = 1 - (Threads_created / Connections)
-- 应该 > 99%

 

参数11: wait_timeout / interactive_timeout

连接空闲超时时间。

 

# 非交互连接的超时时间(应用程序连接)
wait_timeout = 600  # 10分钟

# 交互连接的超时时间(mysql客户端)
interactive_timeout = 3600  # 1小时

 

设置依据

场景 推荐值 说明
Web应用 60-300秒 短连接或连接池
后台服务 600-3600秒 长连接
批处理任务 3600-28800秒 可能长时间运行

参数12: table_open_cache

表文件描述符缓存。

 

# 计算公式:max_connections * 每个连接平均使用表数
# 一般设置为:max_connections * 2 或更多

table_open_cache = 4000
table_open_cache_instances = 16  # 分成多个实例减少锁竞争

 

验证效果

 

-- 查看表缓存状态
SHOW GLOBAL STATUS LIKE 'Open%tables%';
SHOW GLOBAL STATUS LIKE 'Table_open_cache%';

-- Opened_tables 增长过快说明 table_open_cache 太小

 

2.2.3 内存相关参数(参数13-16)

参数13: sort_buffer_size

排序缓冲区大小,用于ORDER BY、GROUP BY操作。

 

# 这是per-session的参数,不要设置太大
# 每个需要排序的查询都会分配一个

sort_buffer_size = 2M  # 推荐值
# 最大不要超过8M,否则可能触发swap

 

常见误区

 

-- 错误:设置太大
-- sort_buffer_size = 256M  # 危险!

-- 假设同时有100个排序查询
-- 内存消耗:100 * 256M = 25.6GB
-- 可能导致OOM或大量swap

 

参数14: join_buffer_size

连接缓冲区大小,用于没有索引的JOIN操作。

 

# 同样是per-session参数
join_buffer_size = 2M

# 注意:如果JOIN有索引,这个参数基本不起作用
# 优化的方向应该是添加合适的索引

 

参数15: tmp_table_size / max_heap_table_size

内存临时表的最大大小。两个参数取较小值生效。

 

# 两个参数应该设置相同
tmp_table_size = 64M
max_heap_table_size = 64M

 

验证效果

 

-- 查看临时表使用情况
SHOW GLOBAL STATUS LIKE 'Created_tmp%';

-- 磁盘临时表比例 = Created_tmp_disk_tables / Created_tmp_tables
-- 应该 < 25%,否则需要增大tmp_table_size
-- 或者优化查询,减少临时表使用

 

参数16: read_buffer_size / read_rnd_buffer_size

顺序读和随机读缓冲区。

 

# 顺序读缓冲区(全表扫描时使用)
read_buffer_size = 1M

# 随机读缓冲区(ORDER BY时使用)
read_rnd_buffer_size = 1M

# 这两个参数也是per-session的
# 默认值128K-256K对大多数场景足够
# 只有确认有大量全表扫描时才需要增大

 

2.2.4 日志与复制参数(参数17-20)

参数17: binlog_cache_size

二进制日志缓冲区大小。

 

# 用于缓存事务的binlog
# 事务过大时会使用临时文件

binlog_cache_size = 4M

# 查看是否需要增大
SHOW GLOBAL STATUS LIKE 'Binlog_cache%';
-- Binlog_cache_disk_use > 0 说明需要增大

 

参数18: sync_binlog

binlog刷盘策略。

 

# 0: 依赖OS刷盘(最快,不安全)
# 1: 每次提交都刷盘(最安全,较慢)
# N: 每N个事务刷盘一次

# 生产环境推荐
sync_binlog = 1

# 与 innodb_flush_log_at_trx_commit 配合
# 双1配置(sync_binlog=1, innodb_flush_log_at_trx_commit=1)
# 是最安全的配置,但性能较差

 

性能与安全的权衡

innodb_flush_log_at_trx_commit sync_binlog 安全性 性能
1 1 最高 最低
2 1 中等
2 100 较高
0 0 最高

参数19: binlog_expire_logs_seconds

binlog自动清理时间(MySQL 8.0+替代expire_logs_days)。

 

# 保留7天的binlog
binlog_expire_logs_seconds = 604800  # 7 * 24 * 3600

# 考虑因素:
# 1. 从库可能的最大延迟时间
# 2. 数据恢复的时间点需求
# 3. 磁盘空间限制

 

参数20: replica_parallel_workers(MySQL 8.0.26+)

从库并行复制Worker数量。

 

# 启用并行复制
replica_parallel_type = LOGICAL_CLOCK
replica_parallel_workers = 16  # CPU核心数的1-2倍
replica_preserve_commit_order = ON

# 主库配合配置
binlog_transaction_dependency_tracking = WRITESET
transaction_write_set_extraction = XXHASH64

 

2.3 启动和验证

2.3.1 配置文件示例

 

# /etc/mysql/mysql.conf.d/optimized.cnf
# MySQL 8.0 优化配置模板
# 适用于:64GB内存,NVMe SSD,16核CPU

[mysqld]
# ===================
# 基础配置
# ===================
server_id = 1
port = 3306
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
tmpdir = /tmp

# 字符集
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci

# ===================
# InnoDB核心参数
# ===================
# 参数1: 缓冲池 - 64GB * 0.75 ≈ 48GB
innodb_buffer_pool_size = 48G

# 参数2: 缓冲池实例 - 每实例约6GB
innodb_buffer_pool_instances = 8

# 参数3: 重做日志容量 (MySQL 8.0.30+)
innodb_redo_log_capacity = 8G

# 参数4: 日志缓冲区
innodb_log_buffer_size = 64M

# 参数5: 日志刷盘策略
innodb_flush_log_at_trx_commit = 2  # 生产可用1

# 参数6: 刷盘方法
innodb_flush_method = O_DIRECT

# 参数7: IO能力
innodb_io_capacity = 10000
innodb_io_capacity_max = 20000

# 参数8: IO线程
innodb_read_io_threads = 8
innodb_write_io_threads = 8

# InnoDB其他优化
innodb_file_per_table = ON
innodb_stats_on_metadata = OFF
innodb_spin_wait_delay = 6
innodb_lock_wait_timeout = 50
innodb_print_all_deadlocks = ON

# ===================
# 连接与线程参数
# ===================
# 参数9: 最大连接数
max_connections = 500

# 参数10: 线程缓存
thread_cache_size = 50

# 参数11: 连接超时
wait_timeout = 600
interactive_timeout = 3600

# 参数12: 表缓存
table_open_cache = 4000
table_open_cache_instances = 16
table_definition_cache = 2000

# ===================
# 内存相关参数
# ===================
# 参数13: 排序缓冲区
sort_buffer_size = 2M

# 参数14: 连接缓冲区
join_buffer_size = 2M

# 参数15: 临时表大小
tmp_table_size = 64M
max_heap_table_size = 64M

# 参数16: 读缓冲区
read_buffer_size = 1M
read_rnd_buffer_size = 1M

# ===================
# 日志与复制参数
# ===================
# 参数17: binlog缓冲区
binlog_cache_size = 4M

# 参数18: binlog刷盘
sync_binlog = 1

# 参数19: binlog保留
binlog_expire_logs_seconds = 604800

# binlog配置
log_bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL

# 参数20: 并行复制(从库配置)
# replica_parallel_type = LOGICAL_CLOCK
# replica_parallel_workers = 16
# replica_preserve_commit_order = ON

# ===================
# 日志配置
# ===================
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = ON

# ===================
# 性能Schema
# ===================
performance_schema = ON
performance_schema_instrument = '%=ON'

 

2.3.2 配置验证脚本

 

#!/bin/bash
# verify_mysql_config.sh
# MySQL配置验证脚本

MYSQL_USER="root"
MYSQL_PASS="your_password"

echo"=== MySQL配置验证 ==="

# 1. 验证InnoDB缓冲池
echo -e "
[1] InnoDB缓冲池配置"
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -N -e "
SELECT
    CONCAT(ROUND(@@innodb_buffer_pool_size/1024/1024/1024, 1), 'G') AS buffer_pool_size,
    @@innodb_buffer_pool_instances AS instances,
    CONCAT(ROUND(@@innodb_buffer_pool_size/@@innodb_buffer_pool_instances/1024/1024/1024, 2), 'G') AS per_instance
"

# 2. 验证缓冲池命中率
echo -e "
[2] 缓冲池命中率"
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -N -e "
SELECT
    CONCAT(
        ROUND((1 - SUM(CASE WHEN VARIABLE_NAME = 'Innodb_buffer_pool_reads' THEN CAST(VARIABLE_VALUE AS DECIMAL) END) /
               SUM(CASE WHEN VARIABLE_NAME = 'Innodb_buffer_pool_read_requests' THEN CAST(VARIABLE_VALUE AS DECIMAL) END)) * 100, 2),
        '%'
    ) AS hit_rate
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN ('Innodb_buffer_pool_reads', 'Innodb_buffer_pool_read_requests')
"

# 3. 验证连接配置
echo -e "
[3] 连接配置"
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -N -e "
SELECT
    @@max_connections AS max_conn,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Max_used_connections') AS max_used,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected') AS current
"

# 4. 验证临时表情况
echo -e "
[4] 临时表使用情况"
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -N -e "
SELECT
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_tables') AS tmp_tables,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_disk_tables') AS disk_tables,
    CONCAT(
        ROUND((SELECT CAST(VARIABLE_VALUE AS DECIMAL) FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_disk_tables') /
              (SELECT CAST(VARIABLE_VALUE AS DECIMAL) FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_tables') * 100, 2),
        '%'
    ) AS disk_pct
"

# 5. 验证IO配置
echo -e "
[5] IO配置"
mysql -u${MYSQL_USER} -p${MYSQL_PASS} -N -e "
SELECT
    @@innodb_io_capacity AS io_capacity,
    @@innodb_io_capacity_max AS io_max,
    @@innodb_read_io_threads AS read_threads,
    @@innodb_write_io_threads AS write_threads
"

echo -e "
验证完成!"

 

三、示例代码和配置

3.1 完整配置示例

3.1.1 不同规格服务器配置模板

小型服务器(8GB内存,4核CPU)

 

# /etc/mysql/mysql.conf.d/small.cnf
# 适用于:8GB内存,4核CPU,SSD

[mysqld]
# InnoDB
innodb_buffer_pool_size = 5G
innodb_buffer_pool_instances = 4
innodb_redo_log_capacity = 2G
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000
innodb_read_io_threads = 4
innodb_write_io_threads = 4

# 连接
max_connections = 200
thread_cache_size = 20
table_open_cache = 1000

# 内存
sort_buffer_size = 1M
join_buffer_size = 1M
tmp_table_size = 32M
max_heap_table_size = 32M

# 日志
binlog_cache_size = 2M
sync_binlog = 1

 

中型服务器(32GB内存,8核CPU)

 

# /etc/mysql/mysql.conf.d/medium.cnf
# 适用于:32GB内存,8核CPU,SSD

[mysqld]
# InnoDB
innodb_buffer_pool_size = 24G
innodb_buffer_pool_instances = 8
innodb_redo_log_capacity = 4G
innodb_log_buffer_size = 32M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_io_capacity = 5000
innodb_io_capacity_max = 10000
innodb_read_io_threads = 8
innodb_write_io_threads = 8

# 连接
max_connections = 500
thread_cache_size = 50
table_open_cache = 2000

# 内存
sort_buffer_size = 2M
join_buffer_size = 2M
tmp_table_size = 64M
max_heap_table_size = 64M

# 日志
binlog_cache_size = 4M
sync_binlog = 1

 

大型服务器(128GB内存,32核CPU)

 

# /etc/mysql/mysql.conf.d/large.cnf
# 适用于:128GB内存,32核CPU,NVMe SSD

[mysqld]
# InnoDB
innodb_buffer_pool_size = 96G
innodb_buffer_pool_instances = 16
innodb_redo_log_capacity = 16G
innodb_log_buffer_size = 128M
innodb_flush_log_at_trx_commit = 1  # 大型系统通常对数据安全要求高
innodb_flush_method = O_DIRECT
innodb_io_capacity = 20000
innodb_io_capacity_max = 40000
innodb_read_io_threads = 16
innodb_write_io_threads = 16

# 连接
max_connections = 2000
thread_cache_size = 100
table_open_cache = 8000
table_open_cache_instances = 32

# 内存
sort_buffer_size = 4M
join_buffer_size = 4M
tmp_table_size = 128M
max_heap_table_size = 128M

# 日志
binlog_cache_size = 8M
sync_binlog = 1

# 其他优化
innodb_page_cleaners = 8
innodb_purge_threads = 8
innodb_lru_scan_depth = 2048

 

3.1.2 动态参数调整脚本

 

#!/usr/bin/env python3
# dynamic_tuning.py
# MySQL动态参数调优脚本

import pymysql
from dataclasses import dataclass
from typing import Dict, List, Tuple
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


@dataclass
class TuningRecommendation:
    """调优建议"""
    parameter: str
    current_value: str
    recommended_value: str
    reason: str
    is_dynamic: bool


class MySQLTuningAdvisor:
    """MySQL调优顾问"""

    def __init__(self, host: str, user: str, password: str, port: int = 3306):
        self.connection = pymysql.connect(
            host=host,
            user=user,
            password=password,
            port=port,
            cursorclass=pymysql.cursors.DictCursor
        )

    def analyze(self) -> List[TuningRecommendation]:
        """分析并生成调优建议"""
        recommendations = []

        # 分析各项指标
        recommendations.extend(self._analyze_buffer_pool())
        recommendations.extend(self._analyze_connections())
        recommendations.extend(self._analyze_temp_tables())
        recommendations.extend(self._analyze_threads())
        recommendations.extend(self._analyze_io())

        return recommendations

    def _get_variable(self, name: str) -> str:
        """获取变量值"""
        with self.connection.cursor() as cursor:
            cursor.execute(f"SHOW VARIABLES LIKE '{name}'")
            result = cursor.fetchone()
            return result['Value'] if result elseNone

    def _get_status(self, name: str) -> int:
        """获取状态值"""
        with self.connection.cursor() as cursor:
            cursor.execute(f"SHOW GLOBAL STATUS LIKE '{name}'")
            result = cursor.fetchone()
            return int(result['Value']) if result else0

    def _analyze_buffer_pool(self) -> List[TuningRecommendation]:
        """分析缓冲池"""
        recommendations = []

        reads = self._get_status('Innodb_buffer_pool_reads')
        read_requests = self._get_status('Innodb_buffer_pool_read_requests')

        if read_requests > 0:
            hit_rate = (1 - reads / read_requests) * 100

            if hit_rate < 99:
                current_size = int(self._get_variable('innodb_buffer_pool_size'))
                recommended_size = int(current_size * 1.5)

                recommendations.append(TuningRecommendation(
                    parameter='innodb_buffer_pool_size',
                    current_value=self._format_bytes(current_size),
                    recommended_value=self._format_bytes(recommended_size),
                    reason=f'缓冲池命中率 {hit_rate:.2f}% 低于99%',
                    is_dynamic=True# MySQL 8.0支持动态调整
                ))

        return recommendations

    def _analyze_connections(self) -> List[TuningRecommendation]:
        """分析连接数"""
        recommendations = []

        max_conn = int(self._get_variable('max_connections'))
        max_used = self._get_status('Max_used_connections')
        usage_rate = max_used / max_conn * 100

        if usage_rate > 80:
            recommendations.append(TuningRecommendation(
                parameter='max_connections',
                current_value=str(max_conn),
                recommended_value=str(int(max_used * 1.5)),
                reason=f'连接使用率 {usage_rate:.1f}% 超过80%',
                is_dynamic=True
            ))
        elif usage_rate < 20and max_conn > 200:
            recommendations.append(TuningRecommendation(
                parameter='max_connections',
                current_value=str(max_conn),
                recommended_value=str(max(200, int(max_used * 2))),
                reason=f'连接使用率仅 {usage_rate:.1f}%,max_connections设置过大',
                is_dynamic=True
            ))

        return recommendations

    def _analyze_temp_tables(self) -> List[TuningRecommendation]:
        """分析临时表"""
        recommendations = []

        tmp_tables = self._get_status('Created_tmp_tables')
        tmp_disk_tables = self._get_status('Created_tmp_disk_tables')

        if tmp_tables > 0:
            disk_ratio = tmp_disk_tables / tmp_tables * 100

            if disk_ratio > 25:
                current_size = int(self._get_variable('tmp_table_size'))
                recommended_size = min(current_size * 2, 256 * 1024 * 1024)  # 最大256MB

                recommendations.append(TuningRecommendation(
                    parameter='tmp_table_size',
                    current_value=self._format_bytes(current_size),
                    recommended_value=self._format_bytes(recommended_size),
                    reason=f'磁盘临时表比例 {disk_ratio:.1f}% 超过25%',
                    is_dynamic=True
                ))

        return recommendations

    def _analyze_threads(self) -> List[TuningRecommendation]:
        """分析线程缓存"""
        recommendations = []

        threads_created = self._get_status('Threads_created')
        connections = self._get_status('Connections')

        if connections > 0:
            thread_cache_hit_rate = (1 - threads_created / connections) * 100

            if thread_cache_hit_rate < 99:
                current_cache = int(self._get_variable('thread_cache_size'))
                recommendations.append(TuningRecommendation(
                    parameter='thread_cache_size',
                    current_value=str(current_cache),
                    recommended_value=str(min(current_cache + 20, 100)),
                    reason=f'线程缓存命中率 {thread_cache_hit_rate:.1f}% 低于99%',
                    is_dynamic=True
                ))

        return recommendations

    def _analyze_io(self) -> List[TuningRecommendation]:
        """分析IO配置"""
        recommendations = []

        # 检查日志等待
        log_waits = self._get_status('Innodb_log_waits')
        if log_waits > 0:
            current_size = int(self._get_variable('innodb_log_buffer_size'))
            recommendations.append(TuningRecommendation(
                parameter='innodb_log_buffer_size',
                current_value=self._format_bytes(current_size),
                recommended_value=self._format_bytes(current_size * 2),
                reason=f'日志缓冲区等待次数 {log_waits}',
                is_dynamic=False# 需要重启
            ))

        return recommendations

    @staticmethod
    def _format_bytes(size: int) -> str:
        """格式化字节数"""
        for unit in ['B', 'K', 'M', 'G']:
            if size < 1024:
                returnf"{size}{unit}"
            size //= 1024
        returnf"{size}T"

    def apply_recommendations(
        self,
        recommendations: List[TuningRecommendation],
        dynamic_only: bool = True
    ) -> Dict[str, bool]:
        """应用调优建议"""
        results = {}

        for rec in recommendations:
            if dynamic_only andnot rec.is_dynamic:
                logger.info(f"跳过非动态参数: {rec.parameter}")
                results[rec.parameter] = False
                continue

            try:
                with self.connection.cursor() as cursor:
                    cursor.execute(
                        f"SET GLOBAL {rec.parameter} = {rec.recommended_value}"
                    )
                    self.connection.commit()
                    logger.info(
                        f"成功调整 {rec.parameter}: "
                        f"{rec.current_value} -> {rec.recommended_value}"
                    )
                    results[rec.parameter] = True
            except Exception as e:
                logger.error(f"调整 {rec.parameter} 失败: {e}")
                results[rec.parameter] = False

        return results

    def generate_report(self, recommendations: List[TuningRecommendation]) -> str:
        """生成调优报告"""
        report = []
        report.append("=" * 60)
        report.append("MySQL参数调优建议报告")
        report.append("=" * 60)

        ifnot recommendations:
            report.append("当前配置良好,无需调整")
        else:
            report.append(f"发现 {len(recommendations)} 项调优建议:
")

            dynamic_params = [r for r in recommendations if r.is_dynamic]
            static_params = [r for r in recommendations ifnot r.is_dynamic]

            if dynamic_params:
                report.append("【可动态调整的参数】")
                for i, rec in enumerate(dynamic_params, 1):
                    report.append(f"
{i}. {rec.parameter}")
                    report.append(f"   当前值: {rec.current_value}")
                    report.append(f"   建议值: {rec.recommended_value}")
                    report.append(f"   原因: {rec.reason}")

            if static_params:
                report.append("
【需要重启生效的参数】")
                for i, rec in enumerate(static_params, 1):
                    report.append(f"
{i}. {rec.parameter}")
                    report.append(f"   当前值: {rec.current_value}")
                    report.append(f"   建议值: {rec.recommended_value}")
                    report.append(f"   原因: {rec.reason}")

        return"
".join(report)


if __name__ == "__main__":
    advisor = MySQLTuningAdvisor(
        host="127.0.0.1",
        user="root",
        password="your_password"
    )

    recommendations = advisor.analyze()
    report = advisor.generate_report(recommendations)
    print(report)

    # 可选:应用动态参数调整
    # results = advisor.apply_recommendations(recommendations, dynamic_only=True)

 

3.2 实际应用案例

3.2.1 案例一:电商大促前的参数调优

场景描述

某电商平台即将迎来双11大促,预计流量是平时的20倍。当前配置是根据日常负载设置的,需要针对大促场景进行调优。

当前配置

 

# 日常配置
innodb_buffer_pool_size = 24G
max_connections = 500
innodb_io_capacity = 2000
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1

 

优化方案

 

# 大促期间配置

# 1. 增大缓冲池应对更多并发读取
innodb_buffer_pool_size = 48G  # 从24G增加到48G

# 2. 增大连接数
max_connections = 2000  # 从500增加到2000

# 3. 提升IO能力
innodb_io_capacity = 10000  # 从2000增加到10000
innodb_io_capacity_max = 20000

# 4. 牺牲少量安全性换取性能
sync_binlog = 100  # 从1改为100
innodb_flush_log_at_trx_commit = 2  # 从1改为2

# 5. 增大临时表大小应对复杂查询
tmp_table_size = 128M
max_heap_table_size = 128M

# 6. 增大排序缓冲区
sort_buffer_size = 4M
join_buffer_size = 4M

 

动态调整脚本

 

#!/bin/bash
# promotion_tuning.sh
# 大促参数切换脚本

MYSQL_CMD="mysql -u root -p'password'"

echo"开始应用大促配置..."

# 动态调整参数
$MYSQL_CMD << EOF
-- 增大连接数
SET GLOBAL max_connections = 2000;

-- 调整IO参数
SET GLOBAL innodb_io_capacity = 10000;
SET GLOBAL innodb_io_capacity_max = 20000;

-- 放宽刷盘策略
SET GLOBAL sync_binlog = 100;
SET GLOBAL innodb_flush_log_at_trx_commit = 2;

-- 增大会话缓冲区
SET GLOBAL sort_buffer_size = 4*1024*1024;
SET GLOBAL join_buffer_size = 4*1024*1024;
SET GLOBAL tmp_table_size = 128*1024*1024;
SET GLOBAL max_heap_table_size = 128*1024*1024;

-- 验证
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'innodb_io_capacity';
SHOW VARIABLES LIKE 'sync_binlog';
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
EOF

echo"大促配置应用完成!"
echo"注意:innodb_buffer_pool_size需要在线扩容或重启"

 

大促后恢复

 

#!/bin/bash
# restore_normal.sh
# 恢复日常配置

MYSQL_CMD="mysql -u root -p'password'"

echo"恢复日常配置..."

$MYSQL_CMD << EOF
SET GLOBAL max_connections = 500;
SET GLOBAL innodb_io_capacity = 2000;
SET GLOBAL innodb_io_capacity_max = 4000;
SET GLOBAL sync_binlog = 1;
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
SET GLOBAL sort_buffer_size = 2*1024*1024;
SET GLOBAL join_buffer_size = 2*1024*1024;
SET GLOBAL tmp_table_size = 64*1024*1024;
SET GLOBAL max_heap_table_size = 64*1024*1024;
EOF

echo"日常配置恢复完成!"

 

3.2.2 案例二:慢查询导致的性能问题排查

问题现象

数据库CPU持续在80%以上,慢查询数量增加,业务响应变慢。

排查步骤

 

-- 1. 查看当前运行的查询
SELECT
    id,
    user,
    host,
    db,
    command,
    time,
    state,
    LEFT(info, 100) ASquery
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDERBYtimeDESC;

-- 2. 分析慢查询日志
-- 使用pt-query-digest分析

-- 3. 查看资源消耗最高的语句
SELECT
    DIGEST_TEXT,
    COUNT_STAR AS exec_count,
    SUM_TIMER_WAIT/1000000000000AS total_sec,
    AVG_TIMER_WAIT/1000000000AS avg_ms,
    SUM_ROWS_EXAMINED AS rows_examined
FROM performance_schema.events_statements_summary_by_digest
ORDERBY SUM_TIMER_WAIT DESC
LIMIT10;

 

发现问题

 

-- 发现大量全表扫描查询
SELECT * FROM orders WHERE status = 'pending'
-- 该表有500万行,status字段没有索引

 

优化方案

 

-- 1. 添加索引
CREATE INDEX idx_status ON orders(status);

-- 2. 临时增大sort_buffer_size应对积压
SET GLOBAL sort_buffer_size = 8*1024*1024;

-- 3. 增大read_buffer_size缓解全表扫描
SET GLOBAL read_buffer_size = 2*1024*1024;

 

参数调优建议

 

# 针对读多写少场景
read_buffer_size = 2M
read_rnd_buffer_size = 2M

# 针对复杂查询场景
sort_buffer_size = 4M
join_buffer_size = 4M
tmp_table_size = 128M
max_heap_table_size = 128M

 

3.2.3 案例三:从库延迟优化

问题现象

从库复制延迟持续在几百秒,影响读写分离架构。

排查命令

 

-- 查看从库状态
SHOW REPLICA STATUSG

-- 关键指标
-- Seconds_Behind_Source: 延迟秒数
-- Relay_Log_Space: 中继日志大小
-- Replica_SQL_Running_State: SQL线程状态

 

发现问题

从库使用单线程复制,无法充分利用多核CPU。

优化方案

 

-- 停止复制
STOP REPLICA;

-- 配置并行复制
SET GLOBAL replica_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL replica_parallel_workers = 16;
SET GLOBAL replica_preserve_commit_order = ON;

-- 启动复制
START REPLICA;

 

从库专用配置

 

# /etc/mysql/mysql.conf.d/replica.cnf
# 从库专用优化配置

[mysqld]
# 并行复制
replica_parallel_type = LOGICAL_CLOCK
replica_parallel_workers = 16
replica_preserve_commit_order = ON

# 从库可以放宽刷盘策略
innodb_flush_log_at_trx_commit = 2
sync_binlog = 0

# 增大IO能力加快回放
innodb_io_capacity = 15000
innodb_io_capacity_max = 30000

# 从库不需要二进制日志(除非级联复制)
# skip_log_bin

# 只读
read_only = ON
super_read_only = ON

 

四、最佳实践和注意事项

4.1 最佳实践

4.1.1 参数调优黄金法则

法则1:先测量后调优

 

# 使用sysbench进行基准测试
sysbench oltp_read_write 
    --mysql-host=127.0.0.1 
    --mysql-user=test 
    --mysql-password=test 
    --mysql-db=sbtest 
    --tables=10 
    --table-size=1000000 
    --threads=32 
    --time=300 
    --report-interval=10 
    prepare

sysbench oltp_read_write 
    --mysql-host=127.0.0.1 
    --mysql-user=test 
    --mysql-password=test 
    --mysql-db=sbtest 
    --tables=10 
    --table-size=1000000 
    --threads=32 
    --time=300 
    --report-interval=10 
    run

 

法则2:单参数调整

每次只调整一个参数,观察效果后再调整下一个。

法则3:记录所有变更

 

-- 创建参数变更记录表
CREATETABLE param_change_log (
    idINT PRIMARY KEY AUTO_INCREMENT,
    changed_at TIMESTAMPDEFAULTCURRENT_TIMESTAMP,
    parameter VARCHAR(100),
    old_value VARCHAR(100),
    new_value VARCHAR(100),
    changed_by VARCHAR(50),
    reason VARCHAR(500)
);

-- 记录变更
INSERTINTO param_change_log (parameter, old_value, new_value, changed_by, reason)
VALUES ('innodb_buffer_pool_size', '24G', '48G', 'dba_john', '大促扩容');

 

4.1.2 内存参数配置原则

 

总可用内存 = 物理内存 * 90%(留10%给OS)

内存分配 =
  innodb_buffer_pool_size (60-70%)
  + max_connections * per_connection_memory (10-20%)
  + 其他缓冲区 (5-10%)
  + OS和其他进程 (10%)

 

per_connection_memory计算

 

-- 每个连接的最大内存消耗
SELECT
    (@@sort_buffer_size + @@join_buffer_size + @@read_buffer_size +
     @@read_rnd_buffer_size + @@binlog_cache_size) / 1024 / 1024 AS per_conn_mb;

-- 最坏情况总消耗
SELECT
    @@max_connections *
    (@@sort_buffer_size + @@join_buffer_size + @@read_buffer_size +
     @@read_rnd_buffer_size + @@binlog_cache_size) / 1024 / 1024 / 1024 AS max_session_memory_gb;

 

4.1.3 IO参数配置原则

存储类型 innodb_io_capacity innodb_io_capacity_max
HDD 7200RPM 200 400
HDD 15000RPM 400-800 1000
SSD SATA 2000-5000 5000-10000
SSD NVMe 10000-50000 20000-100000
云盘SSD 根据规格 根据规格

4.2 注意事项

4.2.1 常见错误

错误配置 问题 正确做法
innodb_buffer_pool_size = 物理内存 OOM 设为物理内存的70-80%
max_connections = 10000 内存耗尽 根据实际需要设置
sort_buffer_size = 256M 单会话内存过大 设为1-4M
innodb_log_file_size太小 频繁checkpoint 设为能容纳1小时日志量
sync_binlog = 0 (生产) 数据丢失风险 生产环境设为1

4.2.2 需要重启的参数

以下参数修改后需要重启MySQL:

 

# 需要重启的参数
innodb_buffer_pool_size        # MySQL 8.0可在线调整
innodb_log_file_size           # 8.0.30前需要重启
innodb_page_size               # 初始化后无法修改
innodb_data_file_path          # 无法在线修改
lower_case_table_names         # 无法在线修改

 

4.2.3 动态参数调整注意事项

 

-- 在线调整buffer_pool_size(MySQL 8.0)
-- 可能需要几分钟完成

SET GLOBAL innodb_buffer_pool_size = 48*1024*1024*1024;

-- 查看调整进度
SHOW STATUS LIKE 'Innodb_buffer_pool_resize_status';

 

五、故障排查和监控

5.1 参数相关问题诊断

 

-- 内存不足诊断
SELECT
    CONCAT(ROUND(@@innodb_buffer_pool_size/1024/1024/1024, 1), 'G') ASbuffer_pool,
    CONCAT(@@max_connections, ' * ',
           ROUND((@@sort_buffer_size + @@join_buffer_size)/1024/1024, 1), 'M = ',
           ROUND(@@max_connections * (@@sort_buffer_size + @@join_buffer_size)/1024/1024/1024, 1), 'G'
    ) AS max_session_memory;

-- 连接数问题诊断
SELECT
    @@max_connections AS max_conn,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Max_used_connections') AS max_used,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Threads_connected') AScurrent,
    (SELECT VARIABLE_VALUE FROM performance_schema.global_status
     WHERE VARIABLE_NAME = 'Aborted_connects') AS aborted;

 

5.2 关键监控指标

指标 健康阈值 查询方法
缓冲池命中率 > 99% Innodb_buffer_pool_read_requests vs reads
连接使用率 < 80% Threads_connected / max_connections
临时表磁盘率 < 25% Created_tmp_disk_tables / Created_tmp_tables
线程缓存命中率 > 99% 1 - Threads_created / Connections
表缓存命中率 > 99% 1 - Opened_tables / Open_tables

5.3 监控脚本

 

#!/bin/bash
# mysql_parameter_monitor.sh
# MySQL参数效果监控脚本

MYSQL_CMD="mysql -u monitor -p'password' -N"

whiletrue; do
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')

    # 收集指标
    result=$($MYSQL_CMD << EOF
SELECT
    ROUND((1 - bp_reads.val / bp_requests.val) * 100, 2) AS buffer_hit_rate,
    ROUND(threads.val / max_conn.val * 100, 1) AS conn_usage,
    ROUND(disk_tmp.val / all_tmp.val * 100, 1) AS disk_tmp_pct
FROM
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') bp_reads,
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests') bp_requests,
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected') threads,
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'max_connections') max_conn,
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_disk_tables') disk_tmp,
    (SELECT CAST(VARIABLE_VALUE AS DECIMAL) AS val FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_tables') all_tmp;
EOF
)

    echo"$timestamp | $result"
    sleep 60
done

 

六、总结

6.1 技术要点回顾

本文详细介绍了MySQL 20个核心参数的调优方法,关键要点如下:

innodb_buffer_pool_size是最重要的参数

设置为物理内存的70-80%

命中率应保持在99%以上

连接相关参数要平衡

max_connections不是越大越好

每个连接都会消耗内存

IO参数要匹配硬件能力

innodb_io_capacity根据磁盘类型设置

SSD和HDD差异巨大

刷盘策略要权衡安全与性能

双1配置最安全但性能较差

根据业务重要性选择合适配置

并行复制大幅提升从库性能

MySQL 8.0的LOGICAL_CLOCK配合WRITESET

Worker数量设置为CPU核心数的1-2倍

6.2 20个参数速查表

序号 参数 推荐值 说明
1 innodb_buffer_pool_size 物理内存70-80% 最重要的参数
2 innodb_buffer_pool_instances 8-16 减少锁竞争
3 innodb_redo_log_capacity 4-8G 8.0.30+新参数
4 innodb_log_buffer_size 64M 日志缓冲区
5 innodb_flush_log_at_trx_commit 1或2 刷盘策略
6 innodb_flush_method O_DIRECT SSD推荐
7 innodb_io_capacity 根据磁盘 IO能力
8 innodb_read/write_io_threads 8 IO线程
9 max_connections 根据需要 最大连接
10 thread_cache_size 50 线程缓存
11 wait_timeout 600 空闲超时
12 table_open_cache 4000 表缓存
13 sort_buffer_size 2M 排序缓冲
14 join_buffer_size 2M 连接缓冲
15 tmp_table_size 64M 临时表
16 read_buffer_size 1M 读缓冲
17 binlog_cache_size 4M binlog缓冲
18 sync_binlog 1 binlog刷盘
19 binlog_expire_logs_seconds 604800 binlog保留
20 replica_parallel_workers 16 并行复制

6.3 参考资料

MySQL 8.0 Reference Manual - Server System Variables https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html

High Performance MySQL, 4th Edition - O'Reilly

MySQL Performance Blog - Percona https://www.percona.com/blog/

MySQL Server Team Blog https://dev.mysql.com/blog-archive/

附录

A. 命令速查表

 

-- 查看所有变量
SHOWVARIABLES;
SHOWGLOBALVARIABLESLIKE'%innodb%';

-- 查看所有状态
SHOWGLOBALSTATUS;
SHOWGLOBALSTATUSLIKE'%Innodb%';

-- 动态修改参数
SETGLOBAL variable_name = value;
SETSESSION variable_name = value;

-- 查看参数是否可动态修改
SELECT * FROM performance_schema.global_variables
WHERE VARIABLE_NAME = 'innodb_buffer_pool_size';

 

B. 配置参数快速对照

场景 关键参数调整
读多写少 增大buffer_pool,减小redo_log
写多读少 增大redo_log,调整刷盘策略
复杂查询 增大tmp_table_size,sort_buffer
高并发 增大connections,thread_cache
从库延迟 parallel_workers,放宽刷盘

C. 术语表

术语 说明
Buffer Pool InnoDB缓冲池,缓存数据和索引
Redo Log 重做日志,保证事务持久性
Checkpoint 检查点,将脏页刷盘的操作
IOPS 每秒IO操作数
TPS 每秒事务数
QPS 每秒查询数

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分