
前阵子一个刚转行做开发的朋友问我“MySQL我装上了也能连上了可我怎么知道它到底跑没跑怎么看数据库里有什么表怎么看某张表有没有数据”我把这几个问题拆开一聊发现其实很多人卡住的不是SQL不会写而是面对一个黑乎乎的MySQL命令行窗口根本不知道从哪下手。这其实就是“mysql怎么查看”这个问题的本质——它不是一个单一操作而是一套和MySQL打交道的核心动作集合。今天这篇就顺着这个思路把“查看”这件事拆透从最基础的版本查看、服务状态查看到库表结构查看、数据查看再到进阶的线程、锁、事务、慢查询日志查看一层一层讲清楚。无论你是刚装上MySQL的小白还是写了两三年SQL想补补基础的同学这篇都能派上用场。后面所有操作我都基于Windows和Linux两种环境分别说明命令也用例子写清楚你可以直接复制去试。1. 先看两件事MySQL到底有没有起来装的是哪个版本1.1 服务状态怎么看Windows和Linux两条路很多新手装完MySQL之后第一步就来一句“mysql -u root -p”结果报了个“Cant connect through socket”或者“Access denied”人就懵了。这不一定是你密码错了很可能是服务压根没启动。Windows下最直观的办法是看服务。按WinR输入services.msc回车在服务列表里找到MySQL服务有的是MySQL80有的是MySQL名称取决于你安装时怎么命名的。状态列显示“正在运行”就没问题显示“已停止”就右键启动。命令行下也可以操作管理员权限打开CMDnet start 服务名 net stop 服务名这里的“服务名”不是显示名称你可以在服务管理器的双击详情里看到“服务名称”。比如MySQL 8.0安装后服务名默认是MySQL80你直接写net start MySQL80就行。我曾经把服务名和显示名搞混敲了一个net start MySQL系统愣是报“服务名无效”排查了半天才发现是自己想当然了。Linux下要看情况。用systemd管理的系统CentOS 7、Ubuntu 16.04、Debian 8用systemctl status mysql # 或者 systemctl status mysqld服务名到底是mysql还是mysqld取决于你装的包。用apt装MariaDB兼容版一般是mysql用Oracle官方yum源装的MySQL通常是mysqld拿不准就systemctl list-units | grep mysql一下一目了然。还有一种更“底层”的确认方式——看端口。无论什么系统MySQL默认监听3306端口所以你可以用这个命令验证服务是否真正监听netstat -tlnp | grep 3306能看到类似tcp6 0 0 :::3306 :::* LISTEN 12345/mysqld的输出说明MySQL是真的起来了而不是只挂了半个进程。这个方法在排查“明明服务显示启动成功但客户端连不上”的场景特别有用。1.2 版本查看客户端版本和服务端版本要分清“我装的MySQL是哪个版本”这个问题看起来简单但里面有个小坑——版本分客户端和服务端两份。有时候你查到的版本号只能说明命令行客户端是什么版本不代表服务端就是这个版本。最权威的查看方式是在成功登录MySQL之后执行SELECT VERSION();返回结果就是个纯版本号比如8.0.46或5.7.44这个反映的是服务端的真实版本。如果不登录就看不了服务端版本吗也不一定。Linux下可以用mysqladmin命令这个工具跟服务端通信一次就能拿到信息不需要交互式登录mysqladmin -uroot -p version输入密码后会输出一坨信息里面有服务端版本号、协议版本、线程数等诊断问题的时候特别好用。Windows下如果你没配置环境变量又不想进到MySQL安装目录的bin文件夹直接在“运行”里敲cmd然后执行mysql --version这时输出的是客户端版本比如mysql Ver 14.14 Distrib 5.7.44, for Win64 (x86_64)。如果你想确认服务端版本还是得走登录后SELECT VERSION();的路子。版本查询还有一个容易忽视的场景——升级后查版本。我用过一台机器跑了两年综合业务某次停机维护升级了MySQL重启后写脚本检查SELECT VERSION()发现还是老版本号排查了半天才发现服务有两个实例升级脚本操作的是A实例而业务连的是B实例。所以升级完一定要用实际业务的连接方式去查版本别想当然。2. 库和表结构怎么查看半天进不去进去别瞎摸2.1 登录后第一件事SHOW DATABASES登录MySQL之后你面对的是一个空白的世界——不像Navicat或者DataGrip那样的图形界面能直接列出所有库命令行里你什么都要主动“问”。先用这条命令看当前实例有哪些数据库SHOW DATABASES;这个列表里通常会包含四个系统数据库information_schema、mysql、performance_schema、sys。MySQL 8.0还多了一个mysql.ibd相关的系统表空间文件但不作为独立数据库显示。新手看到这四个库别慌它们不是给人随便玩的业务库里面存的是元数据、权限信息、性能数据等。你自己的业务库是名字看着和业务相关的那些。选库用USE 库名;注意分号不能少。MySQL命令行把分号当作一条语句的结束标记你写完USE mydb不敲分号再按回车系统不会执行只会换一行继续等待输入。这个细节我曾经在培训时见人卡了十分钟明明敲了命令没反应其实就是忘了分号。2.2 表结构查看DESC和SHOW CREATE TABLE各有用处选定数据库后SHOW TABLES;会列出当前库的所有表。这时候你就能看到具体的表名了。想看某张表的字段结构最常用的是DESC 表名;或者写全称DESCRIBE 表名;输出会显示字段名、类型、是否允许NULL、键类型、默认值、扩展信息一共六列。这套信息就是我们平时建表时写的字段定义只不过用这种形式呈现。但DESC显示的字段结构不够完整它看不到索引的详细信息也看不到存储引擎、字符集、自增起始值这些表属性。想看完整的建表语句就执行SHOW CREATE TABLE 表名\G末尾的\G是个好东西。普通的句末分号会把结果以行列对齐的表格形式输出遇到宽表时列会折行看得眼晕\G会把每条记录纵向展开一条字段一行阅读体验直线上升。这个技巧在查表结构和查复杂查询结果时都非常实用。SHOW CREATE TABLE的输出里除了字段定义还会显示PRIMARY KEY、KEY、ENGINE、CHARSET、AUTO_INCREMENT之类的信息。如果你发现某张表数据量挺大但查询变慢了从这个输出里能直接看出它用的什么存储引擎——MyISAM还是InnoDB——这决定了你对它用什么优化思路。查看表的索引信息用SHOW INDEX FROM 表名;它输出的列很多重点看Key_name索引名、Seq_in_index索引中第几列、Column_name哪一列、Non_unique0代表唯一索引1代表普通索引。排查“为什么这条查询没用上索引”的时候先跑这个命令看看表上到底有哪些索引能省很多无用功。2.3 更进一步information_schema 才是真正的“数据库的数据库”SHOW DATABASES里有个information_schema很多新手从来没进去逛过。这个库很有意思它本身不存业务数据而是存着MySQL所有数据库对象的“元数据”。举个例子你想看当前MySQL实例下一共有多少张表、每张表属于哪个库、每张表的数据量大概多大直接用系统命令行模式挨个SHOW TABLES能查到猴年马月。但这样查就很快SELECT table_schema, table_name, table_rows, engine FROM information_schema.tables WHERE table_schema 你的库名;information_schema.tables这张虚拟表存的就是所有库表的元信息。类似的还有columns表存字段信息、statistics表存索引信息、processlist表存当前线程。我接手老系统时特别喜欢先用这个库扫一圈整体情况哪些表数据量破千万了、哪些表用的还是MyISAM、哪些表没有主键一张SQL全出来比一个个库翻快太多了。这东西就是给你的MySQL拍CT用的。3. 数据查看SELECT是你最该滚瓜烂熟的命令3.1 最简单的查询但细节决定体验数据库里的核心资产是数据查看数据无非就是SELECT。最基本的写法SELECT * FROM 表名 LIMIT 20;很多人写SELECT *时不给LIMIT我见过有同事在几百万行的表上敲SELECT * FROM orders;结果客户端卡死把数据库连接池也拖满了。查询数据时心里一定要有数你只是想看数据长什么样不是想把整个表装进内存。给个LIMIT 20是良好习惯看结果足够了。如果你只想看某些列SELECT id, name, create_time FROM 表名 LIMIT 10;列名用反引号包起来是防止和关键字冲突平常要是你起的字段名叫order、group、desc这类SQL关键字查询时必须加反引号。建议起字段名时就别踩这个坑但也保不齐接手老项目遇到这种表知道了回头就不会奇怪为什么报语法错了。如果表行数特别多LIMIT只能限制返回条数但不能让你快速知道总行数。此时执行SELECT COUNT(*) FROM 表名;注意COUNT(*)统计行数时包含NULL值行COUNT(字段名)则只统计该字段非NULL的行。想知道某字段到底有多少个非空值用后者就对了。3.2 条件查询WHERE的隐形陷阱WHERE是查看数据时最常用的过滤条件了SELECT * FROM 表名 WHERE status 1;字符串条件要用单引号或者双引号括着数字可以裸写。MySQL的字符串比较默认不区分大小写除非你建的字段用了区分大小写的字符集或排序规则否则WHERE name abc能匹配到ABC。这个坑在处理用户输入时容易出大问题尤其在去重、查重场景中要认真考虑大小写敏感性的需求。OR这个条件用法也经常被人问。热搜词里有“mysql的or能去重吗”其实OR的语义很简单满足任一条件即返回该行。它本身不产生重复如果你查出的结果有重复是因为你要查的多列之间有交叉。比如SELECT name FROM 表 WHERE city 杭州 OR city 上海;如果一个用户只有一条城市记录这语句不会出重复。但如果你JOIN了两张表JOIN条件写得不好OR可能在优化器里引发问题结果集出现重复行那就不是你SELECT怎么写的事了而是JOIN写法的问题。总之“OR”不是去重的工具去重要用DISTINCT或者GROUP BY。3.3 查看排序、限制条数ORDER BY和LIMIT的配合排序在你查看数据时几乎避不开。格式是SELECT * FROM 表名 ORDER BY create_time DESC LIMIT 10;DESC倒序ASC正序默认就是ASC可以不写。要注意的是如果你ORDER BY的列没建索引数据量大时排序会非常慢在应用里表现为查询卡顿。排查就是看这条SQL是不是全表扫完再排序。LIMIT有个容易弄混的用法LIMIT offset, row_count。SELECT * FROM 表名 ORDER BY id LIMIT 10, 20;这个意思是跳过前10行从第11行开始取20行。它等价于LIMIT 20 OFFSET 10。很多分页查询就是这么写出来的但不要天真地以为分页查询写个LIMIT 大数, 小数就行——当offset特别大的时候MySQL得先把前offset行都读出来丢掉再取你要的条数性能会很差。经验是大数据量分页不要用这种简单偏移要改用WHERE id 上一页最大id ORDER BY id LIMIT 20这种键集分页。3.4 去重查看DISTINCT、GROUP BY区别在哪去重也是“查看数据”的高频操作。比如你想看某个表里有多少个不同的城市SELECT DISTINCT city FROM 表名;DISTINCT是对整个结果集的每一行去重并非单列去重。如果你写SELECT DISTINCT city, name FROM 表名那是对(city, name)组合去重不是只对city去重。这一点经常有人踩坑说着“我只想去掉city重复的”结果一查name全跟着出来了这不是DISTINCT的锅是你理解错了它的作用域。另一个被反复提及的热词是GROUP BY。它和DISTINCT有点像但语义不同——GROUP BY用于分组配合聚合函数。比如统计每个城市的记录数SELECT city, COUNT(*) FROM 表名 GROUP BY city;GROUP BY的前提是SELECT中出现的非聚合列必须都出现在GROUP BY里。MySQL有一个比较宽松的配置但8.0默认开启了ONLY_FULL_GROUP_BY如果你SELECT的列不在GROUP BY中会直接报错这是好事能帮你避免很多语义不清的查询。3.5 聚合函数、日期处理、字符串函数查看数据的高级姿势热搜词里的“mysql函数大全及举例”也指向这个方向。查看数据时最常用的三个聚合函数是COUNT、SUM、AVGSELECT COUNT(*), SUM(amount), AVG(amount) FROM orders WHERE status paid;日期函数这块DATE_FORMAT能把日期格式化成你想要的字符串比如SELECT DATE_FORMAT(create_time, %Y-%m-%d) FROM orders;热搜那个“mysql datepart”实际上应该对应MySQL的EXTRACT函数或者DATE_FORMATSELECT EXTRACT(YEAR FROM create_time) FROM orders; SELECT DATE_FORMAT(create_time, %Y-%m-%d) FROM orders;MySQL没有SQL Server那种DATEPART函数这是两个产品之间的差异不少从SQL Server转过来的人会在这里搜一圈。字符串函数里最常用的是CONCAT拼接、SUBSTRING截取、REPLACE替换、LENGTH长度。比如查看用户名脱敏SELECT CONCAT(LEFT(name, 1), ***) FROM users;这些函数不改变表中数据只是返回计算结果放心大胆地在SELECT里用。3.6 不敲命令行也行几种GUI工具怎么选你当然可以不只用命令行查看数据。MySQL官方就有MySQL Workbench免费跨平台能看ER图、能跑SQL对新手很友好。还有个更轻量的DBeaver社区版免费连接各类数据库都行界面比Workbench更现代化一些。Navicat功能强大但收费界面舒服中文文档多很多团队在用不过个人学习的话不一定要买可以先从DBeaver下手。我在生产环境排查问题时反而不太用GUI工具因为大多数线上服务器只有命令行环境而且你不可能在客户的生产库上装个图形界面。所以我的建议是把命令行这些查看操作练熟图形界面作为补充工具遇到问题的时候你才不至于被环境限制。4. 不光看数据还要看MySQL本身的状态4.1 SHOW PROCESSLIST查看正在执行的SQL秒杀“为什么卡住了”数据库偶尔会慢尤其是业务高峰期。“查看”数据库正在干什么是定位问题的重要手段。登录MySQL后执行SHOW FULL PROCESSLIST;这会列出当前所有连接和正在执行的SQL语句。重点要看几个列Id是连接IDUser是执行者Host从哪个IP连进来db在哪个库执行Time已执行多少秒State在干什么Info完整的SQL语句。排查“卡住”的常见路径是打开这个命令发现某个SQL的Time已经几百秒了State写Sending data或者Waiting for table metadata lock你马上就知道是哪条SQL拖了后腿。然后按IDKILL掉它KILL 线程ID;这个操作在生产环境要慎重但真有SQL把全库拖死的时候你不得不杀。用SHOW FULL PROCESSLIST扩大眼界还有个变体SELECT * FROM information_schema.processlist;如果你只想看非Sleep状态的连接直接在上面SQL后面加个WHERE COMMAND ! Sleep就行。4.2 锁和事务怎么查锁定、阻塞这类问题一眼定位热搜词“mysql锁的分类”和“mysql锁表”让我想到另一个高频场景——数据库锁等待。MySQL主要分共享锁读锁S锁和排他锁写锁X锁加上意向锁、间隙锁、记录锁这些细致的分类。正常业务中你看到“锁等待”也就是LOCK WAIT状态多半是有事务一直没提交占着行锁不放手后面来的事务只能排队等。查询当前锁等待状态可以执行SHOW ENGINE INNODB STATUS\G这段输出里有一大堆信息其中TRANSACTIONS段落会列出当前活跃事务和锁等待关系。这个命令输出的内容很专业新手可能看不全懂但至少能定位“哪个事务被哪个事务堵住了”。8.0之后也可以用performance_schema下的data_locks和data_lock_waits表来查更结构化的锁信息SELECT * FROM performance_schema.data_locks; SELECT * FROM performance_schema.data_lock_waits;“锁表”这个说法在MySQL里更多指的是表级锁比如MyISAM引擎写时会锁整张表InnoDB如果没用索引条件更新也很容易出现全表锁定的效果。看到“mysql锁表”这种热搜词想知道的八成就是“我的表被锁住了怎么查怎么解”。答案的核心思路还是三步找到持锁事务ID确认它在干什么然后KILL或者等它提交。查当前有哪些处于“卡住”的事务SELECT * FROM information_schema.innodb_trx\Gtrx_state列显示RUNNING还是LOCK WAITtrx_started显示事务开始时间trx_query显示事务正在执行什么。你能从这里直接看到是不是有事务开了很久没提交这种事务是锁等待的常见元凶通常找到对应的SQL和连接就能解决。4.3 慢查询日志把那些拖慢系统的SQL“看”出来数据查看除了看内容还有一个角度看“性能”。MySQL的慢查询日志记录了所有执行时间超过阈值的SQL是性能排查的第一手材料。先看当前慢查询设置SHOW VARIABLES LIKE slow_query_log; SHOW VARIABLES LIKE long_query_time;slow_query_log是ON就说明慢查询日志开着。默认情况下它是OFF的需要手动开启。临时开启重启后失效SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;long_query_time的单位是秒我习惯设成1凡是超过1秒的都记录下来。线上初期骚扰SQL可能比较多你先设3秒也行稳定后再收紧。慢查询日志文件位置可以通过SHOW VARIABLES LIKE slow_query_log_file;查到路径后命令行的方式直接看文件尾部tail -f /var/lib/mysql/机器名-slow.log日志里的每一条SQL都记录了执行耗时、锁等待时间、返回行数、扫描行数。重点看那种扫描行数远超返回行数的SQL——这就是典型的没走对索引的坏SQL是优化重点对象。Windows环境则用记事本打开日志文件也行但日志大了之后最好用专门工具分析比如pt-query-digest不过新手阶段不用急着上这么重的工具先把日志里的TOP几条SQL手动看一遍收获立竿见影。5. 一些零散的“查看”技巧但实用到爆5.1 \G用法再给一次一行太长时救命的显示模式前面提过\G这里还是想单独强调当你执行一条SELECT返回的每条记录有十几个字段时普通分号结尾的表格展示会折行到没法看。比如SELECT * FROM users WHERE id 12345\G这样输出纵向展开user表的id、name、email、phone、status、create_time、update_time等字段一行一个看起来舒服到极致。排查用户数据的时候我从不敲分号全用\G。5.2 查看表数据量、库空间大小一句话摸底部想快速了解业务库占了多少空间一张SQL搞定SELECT table_schema AS db, ROUND(SUM(data_length index_length) / 1024 / 1024, 2) AS size_mb FROM information_schema.tables GROUP BY table_schema;这会列出每个库的总大小MB。同理单独看某张表的大小SELECT table_name, ROUND((data_length index_length)/1024/1024, 2) AS size_mb FROM information_schema.tables WHERE table_schema 你的库名 AND table_name 表名;不开慢查询日志、不上监控平台的时候USER这个办法先粗略扫一下哪些表是大表对业务要有“哪些表是重量级选手”的直觉排查问题时心中才有数。5.3 查看MySQL配置项SHOW VARIABLES连查带改例如想确认字符集SHOW VARIABLES LIKE %character%;想确认隔离级别SHOW VARIABLES LIKE transaction_isolation;MySQL 8.0以上默认隔离级别是REPEATABLE-READ如果你想改成READ-COMMITTED有些业务为了减小锁范围会这么做临时改SET GLOBAL transaction_isolation READ-COMMITTED;改完只对新连接生效正在跑的连接还是旧的。很多人在这一步踩坑——改了配置发现自己的连接还是老隔离级别以为没生效其实是你当前会话缓存的旧变量重新连接就对了。SHOW VARIABLES和SHOW STATUS是两套不同的东西。前者是配置参数我们设置的后者是运行状态计数器数据库实际干活的数据比如Threads_connected当前连接数、Queries累计请求数。排查问题时这两个往往配合用例如连接数飙高时先看SHOW STATUS LIKE Threads_connected再把SHOW PROCESSLIST打开看明细。5.4 查看MySQL错误日志启动失败时的救命稻草装MySQL之后最常见的一个报错是“服务启动失败”网上搜半天看不懂。最直接的排查通道是错误日志。Windows下MySQL的error log路径通常在MySQL安装目录下的data文件夹里文件名类似.err比如C:\ProgramData\MySQL\MySQL Server 8.0\Data\机器名.errLinux下通常在/var/log/mysql/error.log或者/var/lib/mysql/下。用记事本打开或tail你会看到类似“Cant start server: Bind on TCP/IP port. Permission denied”或者“The table mysql is missing”之类的关键信息。这些问题五花八门但错误日志里基本都有线索比在搜索引擎上瞎搜强得多。我排查环境类问题的时候永远是——先看error log然后再决定要不要搜网上的方案。这个顺序一旦反了很可能找到一堆过时的答案。6. 附一份速查表MySQL查看命令大全把上面提到的命令整理成一张表格平时用到直接翻想查看什么命令备注版本SELECT VERSION();登录后的服务端版本服务状态systemctl status mysql / net start MySQLWindows、Linux不同所有数据库SHOW DATABASES;系统库别动切换数据库USE 库名;注意分号当前库所有表SHOW TABLES;先USE再执行表结构DESC 表名;快速看字段完整建表语句SHOW CREATE TABLE 表名\G看索引、引擎索引信息SHOW INDEX FROM 表名;看查询是否用得上索引查数据SELECT * FROM 表名 LIMIT 20;习惯性加LIMIT去重SELECT DISTINCT 字段 FROM 表名;注意作用域排序SELECT * FROM 表 ORDER BY 字段 DESC LIMIT 10;大表排序很吃性能统计数量SELECT COUNT(*) FROM 表名;大表会慢用估算替代当前连接SHOW FULL PROCESSLIST;排查卡顿首选当前事务SELECT * FROM information_schema.innodb_trx\G找长时间未提交事务锁等待SHOW ENGINE INNODB STATUS\G查LOCK WAIT配置项SHOW VARIABLES LIKE %关键词%;通配符模糊匹配慢SQLSHOW VARIABLES LIKE slow_query_log;优化查询第一步库大小查information_schema.tables按table_schema分组错误日志看data目录下.err文件启动失败先看它这张表覆盖了我日常90%的“查看”动作。MySQL版本从5.7到8.0这些命令基本通用只有个别如information_schema.innodb_trx在8.0.2之后有了替代视图但常用部分还是一致的。做数据库排查这几年我最大的感受是“会看”比“会写SQL”更能救火。你辛辛苦苦写一条SQL却发现慢成狗怎么分析先看执行计划再看慢日志再看服务器负载最后落到连接和锁上——这全靠“查看”。如果连怎么查状态都没概念后面的优化分析和事故复盘根本推不下去。最后分享一个我常用的小组合拳。接到“数据库卡了”的告警我先开一个终端敲SHOW FULL PROCESSLIST;看有没有长时间未结束的SQL再敲一条SHOW STATUS LIKE Threads_connected;看连接数有没有飙升最后看SHOW ENGINE INNODB STATUS\G抓有没有锁等待。三条命令跑下来大概率的卡顿原因就已经浮出水面了接下来该杀连接杀连接、该优化SQL优化SQL思路清清楚楚。这套动作熟练之后真就是肌肉记忆治各种“数据库奇慢无比”的毛病屡试不爽。