MySQL是目前最流行的开源关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司。它以高性能、高可靠性、易用性、开源免费著称,被广泛应用于Web开发、企业应用、云计算等领域,是LAMP(Linux+Apache+MySQL+PHP)架构的核心组件之一。

作为一名程序员,数据库是我们日常工作中不可或缺的一部分。但是,很多人对MySQL的使用只停留在基本的增删改查,对数据库优化了解不多。随着数据量的增长和访问量的增加,数据库性能问题会逐渐显现,成为系统的瓶颈。掌握MySQL优化,是程序员的必备技能之一。

今天就来分享MySQL数据库优化的完整指南,从硬件、配置、表结构、索引、SQL语句、架构等多个层面,全面讲解MySQL优化。

MySQL简介

1. 什么是MySQL

MySQL是一种关系型数据库管理系统(RDBMS),使用结构化查询语言(SQL)进行数据管理。它将数据存储在表中,表由行和列组成,表之间可以建立关联关系。MySQL支持事务、索引、视图、存储过程、触发器等高级功能,能够满足各种复杂的应用需求。

MySQL的特点:

  • 开源免费:MySQL是开源软件,可以免费使用和修改,降低了使用成本
  • 性能优异:MySQL性能出色,能够处理大量数据和高并发访问
  • 稳定可靠:MySQL经过长期发展和广泛使用,稳定性和可靠性得到了验证
  • 易用性好:MySQL安装配置简单,学习成本低,易于使用
  • 跨平台:MySQL支持Windows、Linux、macOS等多种操作系统
  • 生态丰富:MySQL有丰富的工具、文档、社区支持,生态完善
  • 支持多种存储引擎:MySQL支持多种存储引擎,如InnoDB、MyISAM、Memory等,可根据需求选择

2. MySQL存储引擎

存储引擎是MySQL中负责数据存储和提取的底层组件,不同的存储引擎有不同的特点和适用场景。

常见的存储引擎:

  • InnoDB:MySQL 5.5+的默认存储引擎,支持事务、行级锁、外键、崩溃恢复,适合大多数应用场景,特别是需要事务支持的应用
  • MyISAM:MySQL 5.5之前的默认存储引擎,不支持事务和行级锁,表级锁,查询速度快,适合读多写少的应用
  • Memory(HEAP):数据存储在内存中,速度极快,但是数据会在重启后丢失,适合缓存、临时数据等场景
  • Archive:只支持INSERT和SELECT,压缩存储,适合归档大量历史数据
  • CSV:数据以CSV格式存储,适合数据交换
  • Blackhole:不存储数据,接收数据但丢弃,用于复制和日志

目前绝大多数应用都使用InnoDB存储引擎,它支持事务、行级锁、外键等高级功能,性能和可靠性都很好。MyISAM已经逐渐被淘汰,不推荐在新项目中使用。

MySQL优化概述

MySQL优化是一个系统工程,涉及多个层面,需要综合考虑。通常可以从以下几个层面进行优化:

  1. 硬件和操作系统优化:CPU、内存、磁盘、网络等硬件资源的配置和优化
  2. MySQL配置优化:MySQL服务器参数的配置和调优
  3. 表结构优化:表设计、字段类型、范式与反范式等优化
  4. 索引优化:索引的设计和使用,是MySQL优化中最重要的部分
  5. SQL语句优化:查询语句的优化,避免慢查询
  6. 架构优化:读写分离、分库分表、缓存、集群等高可用和高性能架构

优化的原则:

  • 先测量,再优化:不要凭感觉优化,先通过监控和分析找到瓶颈,再有针对性地优化
  • 优先优化瓶颈:把精力放在最影响性能的瓶颈上,不要在无关紧要的地方浪费时间
  • 循序渐进:优化要逐步进行,每次只改一个地方,观察效果,避免一次性改太多导致问题
  • 平衡取舍:优化往往需要在性能、成本、复杂度之间做取舍,找到最适合的平衡点
  • 持续监控:优化不是一劳永逸的,需要持续监控,随着业务发展不断调整

硬件和操作系统优化

1. CPU

CPU是数据库性能的重要因素,MySQL是多线程的,能够利用多核CPU。

  • 选择多核、高主频的CPU,MySQL对CPU主频敏感
  • CPU缓存越大越好,大缓存能够提高数据访问效率
  • 避免CPU过载,CPU使用率长期超过80%需要考虑升级或优化

2. 内存

内存是MySQL性能的关键因素,MySQL会将数据和索引缓存到内存中,内存越大,缓存命中率越高,磁盘IO越少,性能越好。

  • 内存越大越好,建议将热数据全部缓存在内存中
  • InnoDB缓冲池(innodbbufferpool_size)是最重要的内存配置,通常设置为物理内存的60%-80%
  • 确保系统不会使用交换分区(swap),swap会严重影响MySQL性能
  • 使用大页(Huge Pages)可以提高内存访问效率,减少TLB miss

3. 磁盘

磁盘IO通常是数据库性能的瓶颈,特别是对于数据量大于内存的场景。

  • 使用SSD(固态硬盘)代替HDD(机械硬盘),SSD的随机读写性能远高于HDD,能够大幅提升数据库性能
  • 使用RAID提高性能和可靠性,如RAID 0(条带化,提高性能)、RAID 1(镜像,提高可靠性)、RAID 10(条带化+镜像,兼顾性能和可靠性)
  • 将数据文件、日志文件、临时文件分别放在不同的磁盘上,分散IO
  • 选择高IOPS的磁盘,数据库对随机IO要求高
  • 合理设置磁盘调度算法,如noop或deadline适合SSD

4. 网络

网络延迟和带宽会影响数据库访问性能,特别是对于分布式架构。

  • 应用服务器和数据库服务器尽量在同一局域网,减少网络延迟
  • 使用千兆或万兆网卡,提高网络带宽
  • 避免跨机房访问数据库,跨机房网络延迟高
  • 合理设置TCP参数,优化网络性能

5. 操作系统优化

  • 使用64位操作系统,支持大内存
  • 关闭不必要的服务和进程,释放系统资源
  • 合理设置文件描述符限制(ulimit -n),MySQL需要打开大量文件
  • 合理设置进程限制,避免MySQL被OOM killer杀死
  • 使用合适的文件系统,如XFS、ext4,XFS更适合大文件和高并发
  • 挂载文件系统时使用noatime选项,减少文件访问时间更新的IO开销

MySQL配置优化

MySQL的配置文件通常是my.cnf(Linux)或my.ini(Windows),合理的配置能够大幅提升MySQL性能。

1. 重要配置参数

[mysqld]
# 基础配置
port = 3306
socket = /tmp/mysql.sock
basedir = /usr/local/mysql
datadir = /data/mysql
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# 连接配置
max_connections = 1000           # 最大连接数,根据并发量调整
max_connect_errors = 100000      # 最大连接错误次数
wait_timeout = 600                # 非交互连接超时时间
interactive_timeout = 600         # 交互连接超时时间
connect_timeout = 10              # 连接超时时间

# InnoDB配置
innodb_buffer_pool_size = 4G      # InnoDB缓冲池大小,最重要的参数,设为物理内存的60%-80%
innodb_buffer_pool_instances = 4   # 缓冲池实例数,多实例减少锁竞争
innodb_log_file_size = 1G          # 重做日志文件大小,影响写入性能和崩溃恢复时间
innodb_log_files_in_group = 2      # 重做日志文件组数量
innodb_flush_log_at_trx_commit = 2 # 日志刷新策略,0=每秒刷新,1=每次提交刷新(最安全),2=每次提交写入os缓存
innodb_file_per_table = 1          # 每个表独立表空间
innodb_flush_method = O_DIRECT     # 数据文件刷新方式,O_DIRECT绕过os缓存,避免双重缓存
innodb_lock_wait_timeout = 50      # 行锁等待超时时间
innodb_io_capacity = 2000          # InnoDB IO能力,SSD可以设大一些
innodb_io_capacity_max = 4000      # 最大IO能力
innodb_read_io_threads = 8         # 读IO线程数
innodb_write_io_threads = 8        # 写IO线程数
innodb_sort_buffer_size = 16M       # 排序缓冲区大小

# MyISAM配置(如果使用MyISAM)
key_buffer_size = 256M              # MyISAM索引缓冲区大小
read_buffer_size = 4M               # 顺序读缓冲区大小
read_rnd_buffer_size = 8M           # 随机读缓冲区大小
sort_buffer_size = 4M               # 排序缓冲区大小
join_buffer_size = 4M               # 连接缓冲区大小
tmp_table_size = 256M               # 临时表大小
max_heap_table_size = 256M          # 内存表最大大小

# 查询缓存(MySQL 8.0已移除)
query_cache_type = 0                # 查询缓存类型,0=禁用,1=启用
query_cache_size = 0                # 查询缓存大小,建议禁用

# 慢查询日志
slow_query_log = 1                  # 开启慢查询日志
slow_query_log_file = /var/log/mysql/slow.log  # 慢查询日志文件
long_query_time = 1                 # 慢查询阈值(秒),超过这个时间的查询会被记录
log_queries_not_using_indexes = 1   # 记录没有使用索引的查询

# 二进制日志(用于复制和恢复)
log_bin = /data/mysql/binlog/mysql-bin  # 二进制日志文件
binlog_format = ROW                 # 二进制日志格式,ROW=行级,STATEMENT=语句级,MIXED=混合
expire_logs_days = 7                # 二进制日志保留天数
max_binlog_size = 1G                # 单个二进制日志文件最大大小
sync_binlog = 1                     # 二进制日志刷新策略,1=每次提交刷新(最安全)

# 错误日志
log_error = /var/log/mysql/error.log  # 错误日志文件

2. 配置优化要点

  • innodbbufferpool_size:这是最重要的参数,设置为物理内存的60%-80%,越大缓存命中率越高,但要留足够内存给操作系统和其他进程
  • innodblogfile_size:重做日志文件大小,影响写入性能,太大会导致崩溃恢复慢,太小会导致频繁刷写,通常设为256M-2G
  • innodbflushlogattrx_commit:日志刷新策略,1是最安全的(每次提交刷新到磁盘),但性能最差;0和2性能更好,但崩溃时可能丢失1-2秒数据,对数据安全性要求不高的场景可以设为2
  • max_connections:最大连接数,不是越大越好,过大可能导致内存不足和上下文切换开销,根据实际并发量设置
  • 慢查询日志:开启慢查询日志,定期分析慢查询,找到需要优化的SQL语句
  • query_cache:查询缓存在高并发写入场景下会导致锁竞争,建议禁用,MySQL 8.0已经移除了这个功能

表结构优化

合理的表结构设计是数据库性能的基础,不好的表结构会导致各种性能问题。

1. 字段类型优化

  • 选择合适的字段类型:在满足需求的前提下,选择最小的数据类型,占用空间越小,性能越好

- 整数:TINYINT(1字节)、SMALLINT(2字节)、MEDIUMINT(3字节)、INT(4字节)、BIGINT(8字节),根据数值范围选择最小的 - 字符串:VARCHAR(变长,节省空间)、CHAR(定长,速度快),VARCHAR长度根据实际需求设置,不要过大 - 日期时间:DATE(3字节)、TIME(3字节)、DATETIME(8字节)、TIMESTAMP(4字节),TIMESTAMP范围小但空间小 - 浮点数:FLOAT(4字节)、DOUBLE(8字节)、DECIMAL(精确小数,适合金额),金额用DECIMAL避免精度问题

  • 避免使用NULL:NULL字段会占用额外空间,查询和索引更复杂,尽量用默认值代替NULL
  • 避免大字段:TEXT、BLOB等大字段会占用大量空间,影响查询性能,如果不需要尽量避免,或者单独拆表
  • 使用枚举类型:对于固定几个值的字段(如性别、状态),可以使用ENUM类型,节省空间且性能好
  • IP地址存储:IP地址可以用INT UNSIGNED存储(用INETATON和INETNTOA转换),比VARCHAR节省空间且查询更快

2. 表设计优化

  • 适度范式化:范式化可以减少数据冗余,保证数据一致性,但是过度范式化会导致多表关联查询,影响性能。建议适度范式化,核心表遵循第三范式,必要时可以适当反范式化(增加冗余字段)减少关联
  • 表不要太大:单表数据量过大(如超过千万行)会导致查询变慢,考虑分表或归档历史数据
  • 字段不要太多:单表字段过多(如超过50个)会影响性能,考虑将不常用的字段拆分到扩展表
  • 选择合适的存储引擎:绝大多数场景使用InnoDB,支持事务和行级锁
  • 设置字符集:统一使用utf8mb4字符集,支持完整的Unicode(包括emoji),避免乱码问题
  • 添加注释:给表和字段添加注释,提高可维护性

3. 主键设计

  • 使用自增主键:InnoDB使用聚簇索引,主键是聚簇索引,自增主键可以保证数据顺序插入,减少页分裂和碎片,性能好
  • 主键尽量小:主键越小,索引占用空间越小,二级索引也越小(二级索引包含主键),查询效率越高
  • 避免使用业务字段作为主键:业务字段可能变化,且可能不是顺序的,影响性能
  • 不要用UUID作为主键:UUID是无序的,会导致随机插入,产生大量页分裂和碎片,性能差且占用空间大

索引优化

索引是MySQL优化中最重要的部分,合理的索引能够大幅提升查询性能,不好的索引会降低写入性能并浪费空间。

1. 索引类型

  • 普通索引(INDEX):最基本的索引,没有任何限制
  • 唯一索引(UNIQUE):索引列的值必须唯一,但允许NULL
  • 主键索引(PRIMARY KEY):特殊的唯一索引,不允许NULL,一个表只能有一个主键
  • 联合索引(复合索引):多个字段组合成的索引,遵循最左前缀原则
  • 全文索引(FULLTEXT):用于全文搜索,适合大文本字段的关键词搜索
  • 空间索引(SPATIAL):用于地理空间数据类型

2. 索引设计原则

  • 最左前缀原则:联合索引遵循最左前缀原则,查询时必须从索引的最左列开始,且不能跳过中间列。例如索引(a,b,c),查询条件a、a+b、a+b+c可以使用索引,b、c、b+c无法使用索引
  • 选择区分度高的列:区分度(不同值的数量/总行数)越高,索引效果越好,主键和唯一键区分度最高。性别等区分度低的列不适合单独建索引
  • 索引列不要参与计算:索引列参与函数或运算会导致索引失效,如WHERE YEAR(createtime)=2016,应该改为范围查询WHERE createtime BETWEEN '2016-01-01' AND '2016-12-31'
  • 避免在索引列上使用函数:和上面一样,函数会导致索引失效
  • 尽量使用覆盖索引:查询的字段都包含在索引中,不需要回表查询数据,性能更好。例如SELECT id, name FROM user WHERE name='xxx',如果name列有联合索引(name, id),就是覆盖索引
  • 控制索引数量:索引不是越多越好,过多的索引会降低写入性能(INSERT/UPDATE/DELETE需要更新所有索引),浪费存储空间。只在需要查询的列上建索引
  • 避免冗余索引:如果已经有索引(a,b),就不需要再建索引(a),因为前者已经包含了后者
  • 前缀索引:对于长字符串列(如VARCHAR(255)),可以只对前N个字符建索引,节省空间,但要注意区分度
  • 定期维护索引:定期分析和优化索引,删除未使用的索引,重建碎片过多的索引

3. 索引使用技巧

-- 查看索引使用情况
SHOW INDEX FROM tablename;

-- 分析查询是否使用索引
EXPLAIN SELECT * FROM tablename WHERE condition;

-- EXPLAIN结果中关注的字段
-- type:访问类型,从好到差:system > const > eq_ref > ref > range > index > ALL
-- key:实际使用的索引,NULL表示没有使用索引
-- rows:扫描的行数,越少越好
-- Extra:额外信息,Using index表示覆盖索引,Using where表示使用WHERE过滤,Using filesort表示需要额外排序,Using temporary表示使用临时表

-- 强制使用索引
SELECT * FROM tablename FORCE INDEX(indexname) WHERE condition;

-- 忽略索引
SELECT * FROM tablename IGNORE INDEX(indexname) WHERE condition;

4. 常见索引失效场景

  • 查询条件使用OR,且OR两边有一列没有索引
  • 联合索引不满足最左前缀原则
  • 索引列使用函数、运算、类型转换
  • 使用LIKE以通配符开头(如'%xxx')
  • 使用!=、<>、NOT IN等负向查询(不一定失效,取决于优化器判断)
  • 字符串不加引号(类型隐式转换)
  • MySQL优化器判断全表扫描比索引更快时(如小表或区分度低)

SQL语句优化

SQL语句的优化直接影响数据库性能,写出高效的SQL是程序员的基本功。

1. 查询优化

  • 只查询需要的列:避免使用SELECT *,只查询需要的字段,减少数据传输和内存使用,更容易使用覆盖索引
  • LIMIT分页:查询列表时使用LIMIT限制返回行数,避免一次返回大量数据
  • 深分页优化:LIMIT 100000, 10这样的深分页效率低,因为需要扫描100010行。可以使用子查询或游标优化:SELECT * FROM table WHERE id > (SELECT id FROM table ORDER BY id LIMIT 100000, 1) LIMIT 10
  • 避免子查询:子查询在某些情况下性能差,尽量用JOIN代替,但不是绝对的,有些场景子查询更高效
  • JOIN优化

- 小表驱动大表,小表在前,大表在后 - JOIN的字段必须有索引 - 尽量减少JOIN的表数量,过多的JOIN会导致查询变慢 - 避免使用LEFT JOIN时在WHERE中过滤右表字段,否则会变成INNER JOIN

  • UNION优化:UNION会去重,需要排序和临时表,性能差;如果不需要去重,使用UNION ALL
  • 避免在WHERE中使用函数:函数会导致索引失效,如WHERE DATE(create_time)='2016-05-20',改为范围查询
  • 合理使用GROUP BY:GROUP BY会排序和使用临时表,性能开销大。如果不需要排序,可以加ORDER BY NULL避免排序
  • 避免大事务:大事务会占用锁时间长,导致锁等待和主从延迟,尽量拆分成小事务

2. 插入和更新优化

  • 批量插入:批量插入比单条插入性能好很多,使用INSERT INTO table VALUES (...), (...), (...)
  • LOAD DATA INFILE:大量数据导入使用LOAD DATA INFILE,比INSERT快很多
  • 关闭自动提交:批量插入时关闭自动提交,手动提交事务,减少事务开销
  • 延迟索引更新:大量数据导入时,可以先禁用索引,导入完成后再重建索引
  • 避免频繁更新:频繁更新会导致锁竞争和IO压力,尽量合并更新
  • UPDATE/DELETE加LIMIT:更新和删除时加LIMIT限制行数,避免长事务和锁表

3. 慢查询分析

-- 开启慢查询日志
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;

-- 查看慢查询日志
-- 直接查看日志文件
-- 或使用mysqldumpslow工具分析
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
-- -s c 按次数排序,-t 10 显示前10条

-- 使用pt-query-digest(Percona Toolkit)分析慢查询,更强大
pt-query-digest /var/log/mysql/slow.log

-- 实时查看正在执行的查询
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;

-- 查看InnoDB状态
SHOW ENGINE INNODB STATUS;

架构优化

当单库单表无法满足性能和可用性需求时,需要从架构层面进行优化。

1. 读写分离

读写分离是将读操作和写操作分离到不同的数据库服务器,主库负责写,从库负责读。MySQL通过主从复制实现数据同步。

  • 适用场景:读多写少的应用,读压力大
  • 优点:分散读压力,提高读性能,提高可用性
  • 缺点:主从延迟,数据不一致风险,架构复杂度增加
  • 实现方式:应用层路由、中间件(如MyCat、ProxySQL、Atlas)

2. 分库分表

当单库单表数据量过大时,需要将数据分散到多个库或多个表中。

  • 垂直分库:按业务模块分库,不同业务的数据放在不同的库中,如用户库、订单库、商品库
  • 垂直分表:按字段分表,将不常用的大字段拆分到扩展表,如用户基本信息表和用户详情表
  • 水平分库:按某个字段(如用户ID)的哈希或范围,将数据分散到多个库中
  • 水平分表:按某个字段的哈希或范围,将数据分散到同一个库的多个表中
  • 适用场景:数据量巨大,单库单表性能瓶颈
  • 优点:分散存储和访问压力,提高性能和容量
  • 缺点:架构复杂,跨库JOIN困难,分布式事务问题,扩容困难
  • 中间件:Sharding-JDBC、MyCat、Vitess等

3. 缓存

缓存是提高数据库性能的重要手段,将热点数据缓存到内存中,减少数据库访问。

  • 应用层缓存:在应用代码中使用本地缓存(如Guava Cache、Caffeine)
  • 分布式缓存:使用Redis、Memcached等分布式缓存系统
  • 数据库缓存:MySQL自身的查询缓存(已废弃)、InnoDB缓冲池
  • 缓存策略:Cache-Aside、Read-Through、Write-Through、Write-Behind
  • 注意事项:缓存穿透、缓存击穿、缓存雪崩、缓存一致性

4. 集群和高可用

  • 主从复制:一主多从,实现读写分离和数据备份
  • 主主复制:双主互备,提高可用性,但需要注意自增ID冲突
  • MHA:MySQL高可用管理工具,实现主库故障自动切换
  • MGR(MySQL Group Replication):MySQL官方的组复制,基于Paxos协议,实现多主写入和高可用
  • Galera Cluster:基于同步复制的多主集群,如Percona XtraDB Cluster、MariaDB Galera Cluster

MySQL监控和诊断

优化的前提是了解数据库的运行状态,监控和诊断是必不可少的。

1. 性能指标

  • QPS(Queries Per Second):每秒查询数,衡量数据库负载
  • TPS(Transactions Per Second):每秒事务数,衡量写入性能
  • 连接数:当前连接数、活跃连接数、最大连接数
  • 缓存命中率:InnoDB缓冲池命中率,越高越好,通常应在99%以上
  • 慢查询数:慢查询的数量和比例,反映SQL质量
  • 锁等待:行锁等待时间和次数,反映锁竞争情况
  • IOPS:磁盘每秒读写次数,衡量磁盘负载
  • 主从延迟:主从复制的延迟时间,反映数据同步情况

2. 常用监控工具

  • MySQL自带:SHOW STATUS、SHOW PROCESSLIST、SHOW ENGINE INNODB STATUS、informationschema、performanceschema
  • 命令行工具:mysqladmin、mysqldumpslow、mysqlslap(压测)
  • 第三方工具

- Percona Toolkit:pt-query-digest、pt-online-schema-change等 - Mytop:类似top的MySQL监控工具 - Innotop:MySQL和InnoDB实时监控工具 - Prometheus + Grafana:主流的监控告警方案,配合mysqld_exporter - Zabbix:企业级监控系统

3. 性能诊断流程

  1. 发现问题:通过监控告警、用户反馈、慢查询日志发现性能问题
  2. 定位瓶颈

- 是CPU瓶颈、内存瓶颈、IO瓶颈还是网络瓶颈? - 是慢查询、锁等待、连接数过多还是缓存命中率低? - 使用SHOW PROCESSLIST查看当前查询,使用EXPLAIN分析慢查询

  1. 分析原因

- 慢查询是因为没有索引、索引失效、SQL写得不好还是数据量太大? - 锁等待是因为事务过大、索引不当还是并发冲突? - 缓存命中率低是因为缓冲池太小还是数据访问不集中?

  1. 优化解决

- SQL优化、索引优化、配置优化、架构优化 - 每次只改一个地方,观察效果

  1. 验证效果

- 优化后重新测试,确认性能提升 - 持续监控,确保没有引入新问题

总结

MySQL优化是一个系统工程,涉及硬件、配置、表结构、索引、SQL、架构等多个层面。优化没有银弹,需要根据具体的业务场景和瓶颈,有针对性地进行优化。

对于大多数应用来说,最重要的优化是:

  1. 合理的表结构设计:选择合适的字段类型,适度范式化
  2. 合理的索引设计:在查询条件上建索引,遵循最左前缀原则,控制索引数量
  3. 高效的SQL语句:避免全表扫描,避免索引失效,只查询需要的列
  4. 充足的内存配置:InnoDB缓冲池足够大,将热数据缓存在内存中
  5. SSD磁盘:使用SSD代替HDD,大幅提升IO性能

掌握MySQL优化,不仅能提升系统性能,还能让我们更深入地理解数据库的工作原理,成为更优秀的程序员。希望这篇指南能帮助大家更好地使用和优化MySQL,让你的数据库跑得更快、更稳。

记住,优化的原则是:先测量,再优化;优先优化瓶颈;循序渐进;平衡取舍;持续监控。不要凭感觉优化,要用数据说话。