慢查询定位与剖析
MySQL性能调优的第一步不是调参数,而是找到真正拖慢系统的SQL。很多运维人员一上来就调整innodb_buffer_pool_size,却忽略了慢查询才是性能瓶颈的根源。开启慢查询日志是最基础的排查手段:
-- Enable slow query log with 1s thresholdSET GLOBAL slow_query_log = ON;SET GLOBAL long_query_time = 1;SET GLOBAL log_queries_not_using_indexes = ON;-- Check slow query log locationSHOW VARIABLES LIKE 'slow_query_log_file';-- Analyze top 10 slow queries-- mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
更高效的方式是直接查询performance_schema,实时获取执行详情:
-- Top SQL by execution timeSELECT DIGEST_TEXT AS sql_text, COUNT_STAR AS exec_count, AVG_TIMER_WAIT/1000000000 AS avg_ms, SUM_ROWS_EXAMINED AS total_rows_scanned, SUM_ROWS_SENT AS total_rows_returned, SUM_ROWS_EXAMINED / COUNT_STAR AS avg_rows_scannedFROM performance_schema.events_statements_summary_by_digestORDER BY SUM_TIMER_WAIT DESCLIMIT 20;
执行计划解读与索引优化
拿到慢SQL后,用EXPLAIN分析执行计划。重点关注type列和Extra列:
-- Full execution planEXPLAIN FORMAT=JSON SELECT o.order_id, o.amount, u.name FROM orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'PAID' AND o.created_at >= '2026-07-01'ORDER BY o.created_at DESC LIMIT 50;
常见问题及优化方案:
type为ALL表示全表扫描,需要添加合适的索引。type为index表示索引全扫描,虽然不是全表扫描但效率依然低。type为range表示索引范围扫描,通常是可接受的。
Extra中出现Using filesort意味着MySQL需要额外排序,这在大数据量下代价极高。解决方案是创建覆盖排序的复合索引:
-- Fix: covering index for sortALTER TABLE orders ADD INDEX idx_status_created (status, created_at);-- Cover query columns to avoid table lookupALTER TABLE orders ADD INDEX idx_status_created_cover (status, created_at, order_id, amount, user_id);
分库分表方案的选择与实施
单表数据量超过5000万行后,即使索引优化到极致,查询延迟也会显著上升。这时需要考虑分库分表。ShardingSphere是目前最成熟的方案,支持分片路由、读写分离和分布式主键。
# ShardingSphere sharding configshardingRule: tables: orders: actualDataNodes: ds_${0..3}.orders_${0..15} tableStrategy: standard: shardingColumn: user_id shardingAlgorithmName: orders-table-mod databaseStrategy: standard: shardingColumn: user_id shardingAlgorithmName: orders-db-mod keyGenerateStrategy: column: order_id keyGeneratorName: snowflake shardingAlgorithms: orders-table-mod: type: MOD props: sharding-count: 16 orders-db-mod: type: MOD props: sharding-count: 4
分片键的选择是分库分表最关键的决策。以user_id作为分片键,所有同一用户的订单落在同一个分表,避免了跨分片JOIN。但这会导致以order_id查询时无法定位分片,需要建立映射表或使用基因法将分片信息编码进order_id。
数据库高可用架构:MGR vs MySQL InnoDB Cluster
MySQL Group Replication(MGR)是官方推荐的高可用方案,支持单主和多主模式。单主模式下,只有主节点接受写操作,从节点自动同步数据并对外提供读服务。MGR基于Paxos协议实现数据一致性,比传统半同步复制更可靠。
# MGR single-primary mode config[mysqld]plugin_load_add = group_replication.sogroup_replication_group_name = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"group_replication_start_on_boot = OFFgroup_replication_local_address = "192.168.1.101:33061"group_replication_group_seeds = "192.168.1.101:33061,192.168.1.102:33061,192.168.1.103:33061"group_replication_single_primary_mode = ONgroup_replication_enforce_update_everywhere_checks = OFF
MGR配合MySQL Router实现自动故障转移,当主节点宕机时,Router自动将写流量切换到新选举的主节点,应用层无需修改连接配置。这是MySQL InnoDB Cluster的核心架构——MGR负责数据复制和主节点选举,Router负责流量路由,MySQL Shell负责集群管理。
SQL查询优化的进阶技巧
避免在WHERE条件中对索引列使用函数,这会导致索引失效。将WHERE YEAR(created_at) = 2026改为WHERE created_at >= ‘2026-01-01’ AND created_at < ‘2027-01-01’。
利用窗口函数替代自连接。例如计算每个用户的最近一笔订单:
-- Window function replaces self-joinSELECT * FROM ( SELECT user_id, order_id, amount, created_at, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn FROM orders) t WHERE rn = 1;
性能调优是一个持续过程,不是一次性的参数调整。建立基线指标、定期审查慢查询、监控关键指标(QPS、连接数、Buffer Pool命中率),才能在问题恶化前及时发现并处理。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql80-xing-neng-diao-you-shi-zhan-cong-man-cha-xun-ding/