
1. 从一次“误删”事故说起为什么你需要了解系统数据库那天下午我正忙着处理一个线上查询性能优化的问题为了快速验证一个索引调整的效果我习惯性地在测试环境里执行了一个DROP DATABASE test_db;。命令执行得飞快但紧接着开发同事的钉钉消息就弹了出来“哥我刚在测试库建的表怎么没了我还没提交代码呢” 我心里咯噔一下赶紧连上数据库查看果然test_db连同里面几个正在开发中的表一起消失了。这不对啊我记得这个库是开发同事自己建的怎么会被我的操作影响排查了一圈才发现问题出在我登录时默认连接的数据库上。我用的账号有全局权限当时默认连接的就是test这个数据库而我手滑把test_db输成了test…… 虽然只是个测试环境但这次“手滑”让我重新审视了 MySQL 安装后那几个默认就存在的数据库。它们不像我们业务库那样显眼却像数据库系统的“神经系统”和“免疫系统”默默支撑着一切。不了解它们你可能会无意中踩坑比如误删了mysql库导致所有用户权限丢失或者因为sys库的视图而困惑于某些监控数据的来源。在 MySQL 8.0 中全新安装后你会默认看到四个系统数据库mysql、information_schema、performance_schema和sys。对于很多刚接触 MySQL 的朋友甚至是一些有经验的开发者可能除了mysql因为要改密码和information_schema偶尔查个表结构之外对另外两个知之甚少更不清楚它们之间如何分工协作。今天我们就来彻底拆解这四位“幕后英雄”搞懂它们各自存了什么、能干什么、以及最重要的——在日常运维和开发中我们该如何与它们安全、高效地打交道。你会发现深入理解它们不仅是避免“误操作”的基础更是你进行性能诊断、安全审计和深度运维的起点。2.mysql数据库的“户口本”与“门禁系统”如果把 MySQL 实例比作一栋大楼那么mysql数据库就是这栋楼的“物业中心”兼“人事档案室”。它存储了所有关于这栋楼如何运行、谁可以进出、以及进出后能干什么的核心元数据。这个数据库是 MySQL 服务启动的基石没有它数据库引擎甚至无法完成初始化。2.1 核心数据字典存储引擎的“导航图”在 MySQL 8.0 之前表结构等元数据一部分存放在.frm文件中另一部分则分散在mysql库的某些表里。这种“双轨制”带来了很多问题比如 DDL数据定义语言操作不是原子性的崩溃后可能导致元数据不一致。MySQL 8.0 的一项重大革新就是引入了事务性数据字典Transactional Data Dictionary。现在所有数据库对象的元数据如表、视图、存储过程、权限等都统一存储在mysql库下的 InnoDB 表中并且这些操作是事务性的。这意味着什么呢举个例子你执行一个ALTER TABLE来增加一个字段并创建索引。在 8.0 之前这个操作可能先写.frm文件再改系统表中间任何一步失败都可能留下“烂尾”工程需要手动修复。而在 8.0 中这个操作被封装在一个事务里要么全部成功元数据被原子性地更新到mysql库的相应表中要么全部回滚表保持原样。这极大地提升了 DDL 操作的可靠性和崩溃恢复能力。虽然这些数据字典表如tablescolumns对用户基本是隐藏的你无法直接SELECT * FROM mysql.tables但你可以通过information_schema或SHOW命令来查询这些信息。mysql库的角色从“部分存储”升级为了“唯一权威存储中心”。2.2 用户与权限体系精细化的“门禁卡”管理这是 DBA 和开发者接触最多的部分。mysql库中有一系列以userdbtables_priv等命名的表共同构成了 MySQL 的权限系统。理解它们的结构对于解决“为什么这个用户没有权限”这类问题至关重要。user表全局通行证。这是最重要的权限表存储了所有用户账户、密码8.0默认使用caching_sha2_password插件加密、以及全局级别的权限如CREATE USERSHUTDOWN。一个用户必须首先在这里有记录才能连接 MySQL 服务器。你可以通过SELECT user, host FROM mysql.user;查看所有用户及其允许登录的客户端主机。db表数据库级门禁。它定义了某个用户对某个特定数据库如app_db拥有的权限。当user表中的全局权限为N时MySQL 会继续检查db表。tables_privcolumns_privprocs_priv表表、列、存储过程级门禁。提供更细粒度的权限控制。比如你可以只允许用户readonly_user查询orders表的idamount两列而不能看customer_phone列。权限的验证是一个自上而下的过程先查user表全局权限如果有则通过如果没有则依次查db-tables_priv-columns_priv。因此在给用户授权时一个常见的坑是你在db表里给用户授予了SELECT权限但user表里对应的全局SELECT权限却是Y。这看起来没问题但如果你后续想收回该用户对某个库的权限仅仅在db表操作是无效的因为全局权限Y会覆盖。最佳实践是对于普通应用用户在user表中只赋予最基本的连接权限如USAGE然后通过GRANT语句在db或更细粒度层级授予具体权限。这样权限管理更清晰也更容易回收。注意永远不要手动使用INSERTUPDATEDELETE语句去直接修改mysql库中的权限表这会导致权限缓存不刷新产生不可预知的行为。必须使用标准的GRANTREVOKECREATE USERALTER USER等 SQL 语句来管理权限MySQL 会自动维护这些表并刷新缓存。2.3 其他关键组件时区、帮助与日志time_zone相关表MySQL 需要知道系统时区和夏令时规则这些信息就存储在mysql.time_zone_namemysql.time_zone等表中。如果你遇到时间字段存储和查询显示不一致的问题很可能就是时区设置不对。通常使用mysql_tzinfo_to_sql工具来加载操作系统时区信息到这些表中。help_表存储了HELP命令的内容。当你输入HELP ‘CREATE TABLE’;时MySQL 就是从这些表里查询并返回语法帮助。general_log与slow_log表如果启用你可以将通用查询日志和慢查询日志的输出目的地设置为TABLE这样日志就会记录到mysql.general_log和mysql.slow_log这两个表中方便用 SQL 进行查询和分析。不过在生产环境出于性能考虑更推荐输出到文件。实操心得备份时mysql库是必须备份的。丢失它意味着丢失所有用户、权限和部分系统配置。可以使用mysqldump --databases mysql进行逻辑备份。但在做任何操作前请再次确认你连接的不是mysql库本身避免重演我的“手滑”悲剧。3.information_schema实时、只读的“系统信息查询接口”如果说mysql库是存储核心元数据的“仓库”那么information_schema就是一个为方便查询而设计的“展示橱窗”。它是一个虚拟数据库里面所有的“表”实际上都是视图VIEW这些视图在查询时动态地从数据字典和其他地方收集信息。它提供了一种符合 ANSI SQL 标准的、只读的方式来访问数据库元数据。3.1 核心特性虚拟、只读与标准化虚拟与实时information_schema不占用实际的磁盘空间来存储数据。每次你查询它它都会实时地去底层获取最新信息。这意味着你查到的永远是当前时刻数据库的状态。只读你无法对其中的任何“表”进行INSERT/UPDATE/DELETE操作这保证了系统信息的安全。标准化它的表结构设计遵循 SQL 标准这使得在不同数据库系统如 PostgreSQL 也有information_schema之间查询元数据的 SQL 语句可以有一定程度的可移植性。3.2 常用视图场景解析它的视图非常多但日常使用主要集中在以下几类探查数据库与表结构-- 查看所有数据库排除系统库 SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN (mysql, sys, information_schema, performance_schema); -- 查看指定数据库如 app_db中的所有表及其存储引擎、行数估算 SELECT TABLE_NAME, ENGINE, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA app_db ORDER BY TABLE_ROWS DESC; -- 查看某张表如 orders的所有列信息 SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA app_db AND TABLE_NAME orders ORDER BY ORDINAL_POSITION;这在数据迁移、生成文档或动态构建 SQL 时非常有用。监控索引与约束-- 查看表的索引情况 SELECT INDEX_NAME, NON_UNIQUE, SEQ_IN_INDEX, COLUMN_NAME, INDEX_TYPE FROM information_schema.STATISTICS WHERE TABLE_SCHEMA app_db AND TABLE_NAME orders; -- 查看外键约束 SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA app_db AND REFERENCED_TABLE_NAME IS NOT NULL;查询进程与锁信息辅助诊断-- 查看当前所有连接/进程 SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND ! Sleep; -- 过滤掉空闲连接 -- 查看当前正在持有的锁需要结合 INNODB_LOCKS 等视图但在8.0中更推荐用 performance_schema注意对于锁和更深入的性能诊断在 MySQL 5.7/8.0 中performance_schema提供了更强大、更细粒度的信息。information_schema中的INNODB_LOCKS等视图在 8.0 中已被标记为 deprecated废弃未来可能会移除。与mysql库的区别简单来说mysql是存储和管理元数据的地方可读写存储核心数据而information_schema是查询和展示这些元数据的一个标准化窗口只读实时视图。例如用户权限信息你通过SHOW GRANTS FOR ‘user’‘host’;查询其背后可能访问了mysql.user等表但通过information_schema没有直接对应的视图来查看权限。4.performance_schema数据库内部的“飞行记录仪”与“仪表盘”这是 MySQL 5.5 版本引入并在后续版本中不断增强的利器。如果说information_schema告诉你数据库里“有什么”那么performance_schema(P_S) 就是告诉你数据库“正在怎么运行”。它像一个内置的、低开销的 profiling性能剖析工具专注于收集数据库服务器运行过程中的性能指标和事件数据。4.1 设计哲学事件驱动与低损耗P_S 的核心设计是事件驱动的。它将数据库的各种活动如语句执行、锁等待、文件I/O、内存分配等抽象为“事件Events”。这些事件被多个“消费者Consumers”收集并存储到一系列以events_开头的表中。它的关键特点是低开销默认配置下P_S 的开销非常低通常5%因为它主要使用内存中的表并且采样机制可配置。深度可观测它能提供从 SQL 语句解析、执行到返回结果的全链路细节包括每个阶段的耗时、使用的资源等。配置灵活你可以通过UPDATE performance_schema.setup_*表来动态调整要监控哪些事件、采样率是多少做到按需采集。4.2 核心应用场景从宏观到微观的性能剖析定位高负载 SQL 不再仅仅依赖慢查询日志有阈值限制P_S 可以记录所有 SQL 的执行情况。-- 查看执行次数最多、总耗时最长的 SQL 摘要类似慢日志的抽象 SELECT digest_text, count_star, sum_timer_wait/1000000000 as total_sec, avg_timer_wait/1000000000 as avg_sec FROM performance_schema.events_statements_summary_by_digest ORDER BY sum_timer_wait DESC LIMIT 10;这个digest_text是 SQL 语句的“指纹”将字面值参数替换为?便于你将同类查询聚合分析。比如SELECT * FROM users WHERE id 1和SELECT * FROM users WHERE id 2会被识别为同一个摘要SELECT * FROM users WHERE id ?。分析锁竞争 在并发高的场景下锁等待是性能杀手。P_S 可以清晰地告诉你谁在等谁。-- 查看当前正在等待的锁需要启用相关instruments和consumers SELECT waiting.thread_id as waiting_thread, waiting.event_id as waiting_event, blocking.thread_id as blocking_thread, blocking.event_id as blocking_event FROM performance_schema.data_lock_waits waits JOIN performance_schema.threads waiting ON waits.requester_thread_id waiting.thread_id JOIN performance_schema.threads blocking ON waits.holder_thread_id blocking.thread_id;这比SHOW ENGINE INNODB STATUS的输出更结构化更容易编写自动化脚本进行分析。监控内存使用 MySQL 8.0 的 P_S 对内存监控的支持非常完善。-- 按内存分配类型排序查看哪些组件消耗内存最多 SELECT event_name, current_count, current_alloc, high_alloc, high_count FROM performance_schema.memory_summary_global_by_event_name ORDER BY current_alloc DESC LIMIT 10;这对于诊断内存泄漏或异常内存增长非常有帮助。分析文件 I/O 了解数据库的磁盘 I/O 模式。-- 查看文件 I/O 的延迟统计 SELECT file_name, event_name, count_read, sum_timer_read/1000000000 as total_read_sec, count_write, sum_timer_write/1000000000 as total_write_sec FROM performance_schema.file_summary_by_instance ORDER BY (sum_timer_readsum_timer_write) DESC LIMIT 10;实操心得P_S 功能强大但表众多初次接触容易迷茫。建议从setup_*表开始了解如何启用你需要的监控项instruments和消费者consumers。通常生产环境不会全量开启所有监控而是按需开启。一个常见的做法是长期开启events_statements_summary_by_digest用于 SQL 分析在出现性能问题时再动态开启更细粒度的等待事件或阶段事件监控来定位瓶颈。5.sysDBA 与开发者的“性能仪表盘”与“自动化诊断报告”sys数据库是 MySQL 5.7 版本引入的它基于performance_schema和information_schema通过一系列视图、存储过程和函数将底层复杂的性能数据转化为人类可读、DBA 可直接使用的诊断报告。你可以把它理解为 P_S 的一个“友好图形界面”虽然它还是命令行或者一个预置了最佳实践的“专家系统”。5.1 核心价值化繁为简直击要害P_S 提供了海量数据但直接查询其原始表可能很繁琐。sys库帮你做好了聚合、关联和格式化。例如你想知道“哪个主机对我的数据库造成了最大的负载”在 P_S 中可能需要关联好几张表而在sys中只需一个简单的查询SELECT * FROM sys.host_summary ORDER BY statements DESC LIMIT 5;它会清晰地列出每个客户端主机的连接数、执行的语句总数、延迟、锁等待时间等一目了然。5.2 常用视图与函数场景快速健康检查sys.metrics: 查看各种全局指标类似SHOW GLOBAL STATUS但更规整包含了一些计算好的比率。sys.innodb_buffer_stats_by_schema: 查看每个数据库模式在 InnoDB 缓冲池中占用了多少页面这对于评估数据“热度”和调整缓冲池大小很有参考价值。-- 查看缓冲池命中率这是一个metric SELECT variable_value FROM sys.metrics WHERE variable_name buffer_pool_hit_ratio;SQL 与 IO 问题诊断sys.statement_analysis: 类似于events_statements_summary_by_digest的增强版直接给出了“全表扫描次数”、“临时表使用情况”、“排序行数”等对优化师至关重要的信息并已经按总延迟排序好。sys.io_global_by_file_by_bytes/sys.io_global_by_file_by_latency: 从字节数或延迟角度快速定位哪个文件可能是表文件、日志文件的 I/O 压力最大。-- 找出全表扫描最多的 SQL SELECT query, db, exec_count, rows_examined_avg, rows_sent_avg FROM sys.statement_analysis WHERE rows_examined_avg 10000 -- 假设阈值是1万行 ORDER BY rows_examined_sum DESC LIMIT 5;内存与锁分析sys.memory_by_host_by_current_bytes: 按连接主机统计内存使用。sys.schema_table_lock_waits: 直接展示当前发生的表级锁等待关系比查询 P_S 原始表直观得多。-- 查看当前正在等待的元数据锁MDL SELECT * FROM sys.schema_table_lock_waits\G这个命令在解决“SHOW PROCESSLIST里看到大量Waiting for table metadata lock”的问题时是首选利器。强大的存储过程sys.ps_trace_thread(): 对指定线程进行性能跟踪生成一个详细的报告文件。sys.statement_performance_analyzer(): 创建当前负载的快照并与之前的快照进行对比用于分析负载变化。与performance_schema的关系sys库完全依赖于performance_schema和information_schema。它不存储任何新数据只是提供了一种更便捷的查询方式。如果performance_schema没有启用或没有收集相关数据那么sys库的相应视图将返回空或错误数据。因此要使用sys必须先确保performance_schemaON。个人使用习惯在日常巡检和故障排查时我通常会先打开sys库用几个关键视图如host_summarystatement_analysisschema_table_lock_waits进行快速扫描定位大致方向。如果问题比较复杂需要更深度的数据再转向performance_schema的原始表进行定制化查询。sys极大地降低了对 P_S 的学习曲线是每个 MySQL DBA 都应该熟练掌握的工具。6. 四大系统库的协同与运维要点理解了每个库的职责后我们来看看它们是如何协同工作的以及在运维中需要注意什么。6.1 协同工作流一次查询的幕后之旅假设一个客户端执行SELECT * FROM app_db.orders WHERE user_id 100;。连接与认证客户端发起连接。MySQL 服务端查询mysql.user表验证用户名、密码和来源主机是否有连接权限。权限验证连接建立后服务器检查该语句。它首先查看mysql.user中的全局SELECT权限如果没有则继续检查mysql.db表中该用户对app_db库的权限可能还会检查mysql.tables_priv对orders表的权限。元数据获取优化器需要知道orders表的结构、索引等信息。它通过查询事务性数据字典存储在mysql库的底层表中或通过information_schema的接口获取这些信息。语句执行与监控语句开始执行。如果performance_schema启用了语句事件监控那么从解析、优化、执行到返回的每个阶段其耗时和资源使用情况都会被记录到events_statements_*系列表中。I/O与锁监控如果语句需要读取数据页P_S 的文件 I/O 监控可能会记录这次读取。如果涉及锁锁等待事件也会被记录。诊断与查看事后DBA 可以通过sys.statement_analysis视图其数据来源于 P_S来查看这条 SQL 的聚合性能指标或者通过information_schema.processlist查看它执行时的状态。6.2 备份、恢复与迁移注意事项备份mysql必须备份。这是用户和权限的根源。information_schema和performance_schema无需备份。它们是虚拟的或基于内存的重启或重建实例时会自动生成。sys无需备份。它只是视图和存储过程。你可以备份其定义DDL但数据本身来自 P_S 和 I_S。使用mysqldump备份整个实例时--all-databases会自动包含mysql和sys的定义并排除information_schema和performance_schema。这是正确的行为。恢复恢复mysql库后必须执行FLUSH PRIVILEGES;命令或者在重启 MySQL 实例以确保内存中的权限缓存与磁盘数据同步。迁移如版本升级mysql表结构可能在主版本升级如 5.7 - 8.0时发生变化。官方升级工具mysql_upgrade的核心任务之一就是检查并升级mysql系统表的结构。在升级前务必阅读官方升级文档中对mysql库的处理说明。sys在升级 MySQL 主版本后通常需要手动更新sys库。因为新版本的 P_S 可能新增了表或列sys的视图需要与之匹配。可以使用mysql_upgrade它会处理或手动执行sys源码包中的sys_56_in_57.sql之类的升级脚本。6.3 安全与权限管理默认权限初始的root用户拥有对所有系统库的完全权限。对于普通应用账号绝对不要授予对mysqlperformance_schemasys的写权限甚至读权限很多时候也不需要。information_schema的SELECT权限通常可以开放因为它只是只读视图。监控账号可以创建一个仅用于监控的数据库账号并授予其对performance_schema和sys库的只读权限有时也需要PROCESS全局权限这样监控系统如 Prometheus mysqld_exporter就可以安全地采集性能数据而无需使用高权限的root账号。6.4 性能考量与配置调优performance_schema的内存占用P_S 使用内存表其大小由一系列performance_schema_max_*系统变量控制如performance_schema_max_digest_lengthperformance_schema_events_statements_history_size。在内存受限的环境中需要合理配置这些参数在可观测性和内存消耗之间取得平衡。默认配置通常适用于大多数场景但如果需要开启更多监控项如所有阶段的语句事件内存消耗会增加。information_schema的查询开销虽然 I_S 是视图但复杂查询例如关联多张大型表的TABLES和STATISTICS视图也可能对性能产生一定影响因为它需要实时收集和关联大量元数据。在极高并发或对元数据查询非常频繁的场景下需要注意这一点。7. 实战利用系统数据库解决一个线上慢查询问题让我们模拟一个真实的场景串联使用这几个系统库。假设监控报警显示数据库 CPU 使用率持续超过 80%我们需要快速定位问题。第一步快速概览 (sys库上场)首先连接到sys库进行快速扫描。USE sys; -- 1. 查看哪个主机或用户消耗资源最多 SELECT * FROM host_summary ORDER BY statement_latency DESC LIMIT 3; -- 假设发现来自应用服务器 10.0.0.5 的连接总延迟最高。 -- 2. 查看哪些 SQL 语句是“罪魁祸首” SELECT query, db, exec_count, total_latency, rows_examined_avg, rows_sent_avg FROM statement_analysis ORDER BY total_latency DESC LIMIT 5; -- 假设发现一条关于 user_actions 表的查询总延迟非常高且平均检查行数 (rows_examined_avg) 远大于返回行数 (rows_sent_avg)暗示可能存在全表扫描或索引不佳。通过sys我们在 30 秒内就将问题范围缩小到了特定 IP 的特定 SQL 上。第二步深入分析 SQL 细节 (performance_schema上场)现在我们需要更详细的信息。记下sys.statement_analysis中问题 SQL 的digest值一个哈希值。USE performance_schema; -- 通过摘要指纹查看该SQL的详细执行统计 SELECT * FROM events_statements_summary_by_digest WHERE digest ‘问题SQL的digest值’\G -- 这里可以看到更详细的统计总耗时、最小/最大耗时、锁等待时间、错误次数等。 -- 如果想看该SQL最近一次或几次的具体执行计划如果开启了events_statements_history SELECT thread_id, event_id, sql_text, rows_examined, rows_sent, timer_wait/1000000000 as exec_sec FROM events_statements_history WHERE digest ‘问题SQL的digest值’ ORDER BY event_id DESC LIMIT 3;第三步检查表结构与索引 (information_schema上场)怀疑索引问题我们来检查user_actions表的结构和索引。USE information_schema; -- 查看表结构 SELECT COLUMN_NAME, DATA_TYPE, COLUMN_KEY FROM COLUMNS WHERE TABLE_SCHEMA ‘your_db’ AND TABLE_NAME ‘user_actions’ ORDER BY ORDINAL_POSITION; -- 查看现有索引 SELECT INDEX_NAME, NON_UNIQUE, SEQ_IN_INDEX, COLUMN_NAME, INDEX_TYPE FROM STATISTICS WHERE TABLE_SCHEMA ‘your_db’ AND TABLE_NAME ‘user_actions’ ORDER BY INDEX_NAME, SEQ_IN_INDEX;通过对比 SQL 的WHERE条件和现有索引我们可能发现缺少了针对某个字段的索引。第四步实施修复与验证根据分析我们决定为user_actions表的action_type和created_at字段添加一个复合索引。USE your_db; ALTER TABLE user_actions ADD INDEX idx_type_created (action_type, created_at);添加索引后我们再次通过sys.statement_analysis观察该 SQL 的rows_examined_avg是否下降total_latency增长趋势是否放缓。同时也可以回到performance_schema查看最新的执行事件确认延迟是否降低。第五步权限与用户检查如需mysql库上场在整个过程中如果我们用于诊断的监控账号权限不足比如无法查询sys或performance_schema我们就需要连接mysql库使用GRANT语句为其授权。USE mysql; -- 假设我们创建一个监控用户 CREATE USER ‘monitor’‘10.0.0.%’ IDENTIFIED BY ‘StrongPassword!’; GRANT SELECT ON performance_schema.* TO ‘monitor’‘10.0.0.%’; GRANT SELECT ON sys.* TO ‘monitor’‘10.0.0.%’; GRANT PROCESS ON *.* TO ‘monitor’‘10.0.0.%’; -- 允许查看 PROCESSLIST通过这个实战流程你可以看到四个系统数据库并非孤立存在而是在数据库运维的生命周期中各司其职协同工作。sys提供快速入口和聚合视图performance_schema提供深度剖析的原始数据information_schema提供对象结构的快照而mysql则保障了整个系统的访问控制和基础元数据管理。掌握它们你就拥有了从宏观到微观全面掌控 MySQL 数据库运行状态的能力。