在MySQL日常运维和开发排查中,我们常常需要了解某个具体数据库下有哪些表,以及这些表的存储引擎、大致行数、创建时间和字段构成。如果每次都手动执行show tables再逐张describe,不仅繁琐还容易遗漏。通过创建一个接收数据库名称作为参数的存储过程,可以把这些信息一次性整理输出,大幅提升效率。

一、核心思路与用到的系统表
MySQL把元数据集中在information_schema库中。其中tables表记录了每个表的库名、表名、引擎、表行数估算和创建时间;columns表则记录了字段名、类型、是否可为空等。我们的存储过程只需要以传入的数据库名为过滤条件,关联这两张表即可。
需要注意,information_schema中的table_rows只是基于统计信息的估算值,对于InnoDB表尤其不准,仅适合做粗粒度参考。若需要精确行数,应额外对具体表执行count,但那会显著降低存储过程性能,因此本例仅取估算值。
1.1 权限要求
执行该存储过程的用户必须对information_schema有查询权限,且对目标数据库有某种访问权限。若权限不足,查询会返回空结果集而不是报错,这一点在调试时要留心。
另外,存储过程定义者权限(definer)和调用者权限(invoker)会影响实际能查到的库范围。建议使用invoker权限创建,避免高权限账号被普通调用者间接利用。
二、存储过程完整代码
下面给出一个可直接在MySQL 5.7及以上版本运行的存储过程。它接收一个数据库名参数,先列出表级信息,再使用游标把每个表的字段信息逐行输出。
DELIMITER $$
CREATE PROCEDURE list_db_tables_detail(IN db_name VARCHAR(64))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE t_name VARCHAR(64);
DECLARE cur CURSOR FOR
SELECT table_name
FROM information_schema.tables
WHERE table_schema = db_name
ORDER BY table_name;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- 输出表级概览
SELECT
table_name AS '表名',
engine AS '引擎',
table_rows AS '估算行数',
create_time AS '创建时间'
FROM information_schema.tables
WHERE table_schema = db_name
ORDER BY table_name;
-- 遍历每张表输出字段详情
OPEN cur;
read_loop: LOOP
FETCH cur INTO t_name;
IF done THEN
LEAVE read_loop;
END IF;
SELECT
t_name AS '所属表',
column_name AS '字段名',
column_type AS '字段类型',
is_nullable AS '可为空',
column_key AS '键类型'
FROM information_schema.columns
WHERE table_schema = db_name
AND table_name = t_name
ORDER BY ordinal_position;
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
2.1 代码关键点说明
上述代码使用DELIMITER改写了语句结束符,确保存储过程体内部的分号不会被客户端提前解析。参数db_name类型设为VARCHAR(64),因为MySQL库名和表名最大长度就是64字符。
游标部分先查出该库所有表名,再在循环中对每张表查columns。虽然可以一次性用join查出所有字段,但分表输出在命令行里可读性更好,也方便调用者按表复制结果。
三、调用方式与输出示例
假设我们有一个名为shop的数据库,只需执行如下语句即可看到详细清单:
CALL list_db_tables_detail('shop');
第一个结果集类似:
表名 引擎 估算行数 创建时间 orders InnoDB 1520 2023-04-11 10:22:01 users InnoDB 8930 2023-04-11 10:21:33
随后会紧跟着每个表各自的字段结果集。在MySQL命令行客户端中,多个结果集会顺序打印;在编程语言里如JDBC,则需要通过getMoreResults方法依次读取。
3.1 避免误查系统库
如果传入的db_name是mysql、information_schema或performance_schema,过程也会输出,但内容对业务无意义。可在过程开头加一句判断:
IF db_name IN ('mysql','information_schema','performance_schema','sys') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '禁止查看系统库';
END IF;
这样能在入口处拦截明显不合理的调用,减少误操作。生产环境建议保留此类防护,尤其是当存储过程暴露给自动化平台时。
四、优缺点与适用场景
这种存储过程的优势是逻辑集中在数据库侧,应用层只需一次CALL就能拿到结构全景,非常适合做库表巡检脚本、生成文档或接手陌生项目时的快速摸排。
缺点是输出多个结果集,部分轻量ORM框架不支持方便地处理;另外对超大实例(几千张表)而言,循环查columns会产生较多独立查询。此时可改为单条join语句并让调用端自行分组,换取更高性能。
4.1 性能优化变体
若表数量极多,可去掉游标,直接用一张临时表或单一查询:
SELECT
t.table_name,
t.engine,
t.table_rows,
c.column_name,
c.column_type
FROM information_schema.tables t
JOIN information_schema.columns c
ON t.table_schema = c.table_schema
AND t.table_name = c.table_name
WHERE t.table_schema = db_name
ORDER BY t.table_name, c.ordinal_position;
该写法只发一条SQL,由MySQL优化器决定访问路径,在万级表场景下明显更快,但结果需调用者在内存中按表名拆分展示。
MySQLstored_procedureinformation_schema修改时间:2026-08-04 12:06:31