在数据库日常管理中,了解当前实例上有多少客户端连接、这些连接处于什么状态,是判断系统负载和排查连接泄漏的基础工作。SQL语言本身不提供统一的函数来返回连接数,但每种主流数据库都暴露了内部的系统表或系统视图,只要用一条聚合查询就能拿到结果。

一、MySQL中通过COUNT(*)统计连接进程
MySQL把每一个客户端连接看作一个服务器线程,相关信息存放在information_schema库下的PROCESSLIST表(某些版本也提供SHOW PROCESSLIST命令)。这张表实时反映当前所有线程,包括正在执行的查询和处于Sleep状态的空闲连接。我们只需对其做计数即可。
需要注意,普通用户执行对PROCESSLIST的查询时,只能看到自己权限范围内的线程;拥有PROCESS权限的账号才能看到全部连接。因此监控脚本务必使用具备该权限的专用账号,否则统计值会偏小,造成误判。
-- 统计MySQL当前所有可见连接数 SELECT COUNT(*) AS connection_count FROM information_schema.PROCESSLIST; -- 仅统计非Sleep状态的活跃连接 SELECT COUNT(*) AS active_count FROM information_schema.PROCESSLIST WHERE COMMAND <> 'Sleep';
上面的第二条语句在实际运维中更有参考价值。很多连接池会维持大量Sleep连接,若把它们全部算进“进程数量”,会掩盖真正的并发压力。通过过滤COMMAND字段,可以把空闲连接排除。
另外,MySQL还提供了全局状态变量Threads_connected,用SHOW STATUS LIKE 'Threads_connected'也能获取连接数。它与PROCESSLIST的COUNT(*)通常一致,但前者是状态快照,后者是明细表,后者能进一步按HOST、USER分组分析。
二、PostgreSQL的pg_stat_activity视图
PostgreSQL使用pg_stat_activity系统视图来展示每个后端进程的信息。和MySQL类似,它也是一行代表一个连接。不过PostgreSQL默认允许任何用户查看自己的连接,超级用户才能看全部,这一点在编写统计SQL时要留意。
除了简单的计数,PostgreSQL的state字段明确区分了active、idle、idle in transaction等状态,比MySQL的COMMAND更细致。我们可以用CASE表达式分别统计,帮助判断是否有事务长期未提交导致连接占用。
-- 统计PostgreSQL当前总连接数 SELECT COUNT(*) AS total_connections FROM pg_stat_activity; -- 按状态分类统计 SELECT state, COUNT(*) AS cnt FROM pg_stat_activity GROUP BY state ORDER BY cnt DESC;
如果数据库设置了max_connections限制,还可以用一条语句算出使用率,便于配置告警阈值。例如将COUNT(*)除以当前设置值,得到百分比。
在云环境或容器化部署中,pg_stat_activity偶尔会因为连接风暴而查询变慢,此时可以结合pgbouncer等连接池的自身统计,交叉验证数字准确性。
三、SQL Server的动态管理视图
SQL Server提供一组以sys.dm_开头的动态管理视图,其中sys.dm_exec_sessions记录了所有会话,sys.dm_exec_connections记录物理连接。由于一个会话可能对应多个连接,统计进程数量时一般查sessions更贴近“连接用户数”的概念。
SQL Server的视图权限控制较严格,需要VIEW SERVER STATE权限才能查询全部行。下面示例展示了如何统计并排除系统内部会话。
-- 统计SQL Server非系统会话连接数 SELECT COUNT(*) AS user_session_count FROM sys.dm_exec_sessions WHERE is_user_process = 1; -- 查看各数据库的连接分布 SELECT DB_NAME(database_id) AS db_name, COUNT(*) AS sess_cnt FROM sys.dm_exec_sessions WHERE is_user_process = 1 GROUP BY database_id ORDER BY sess_cnt DESC;
通过is_user_process字段,可以轻松把系统后台会话剥离,得到真实业务连接数。如果需要更细的执行状态,可关联sys.dm_exec_requests查看正在运行的请求。
在AlwaysOn或镜像环境下,某些会话属于高可用机制,也应视为系统进程,避免监控误报。理解各字段含义,是准确统计的前提。
四、COUNT(*)查系统表的局限与建议
用COUNT(*)查系统表的确简单直接,但它不是没有代价。系统表本质是数据库内部状态的投影,高频轮询可能对元数据锁或内存产生轻微影响;在连接数极高时,聚合全表也会消耗少量CPU。因此监控间隔不宜过短,通常30秒到1分钟一次足够。
另一个常见误区是把所有查出来的行都当成“进程”。在多线程架构的数据库中,连接和操作系统进程并非一一对应;SQL里的“进程数量”实际是逻辑连接数。明确这一概念,才能和运维同学的操作系统级监控对得上号。
-- 通用监控片段示例(以MySQL为例,带时间戳) SELECT NOW() AS ts, COUNT(*) AS cnt FROM information_schema.PROCESSLIST WHERE COMMAND <> 'Sleep';
最后建议将统计结果存入时序表,配合图表观察连接数曲线。一旦发现异常增长,可立即从系统表取出对应HOST或PROGRAM_NAME,定位问题服务。掌握上述各库的COUNT(*)写法,基本能覆盖绝大部分连接统计场景。