<p>先确认是否表被锁:执行SHOW PROCESSLIST(MySQL)或SELECT * FROM pg_stat_activity WHERE state='active' OR wait_event_type='Lock'(PostgreSQL),重点查State为Locked、idle in transaction或Info含未提交SQL的进程;再谨慎KILL阻塞线程,避免误杀系统进程。</p>
Navicat里查不到“表被锁定”错误,但查询卡死或加载不出?先看锁状态
navicat 本身不报“表被锁定”这种明确提示,而是表现为:点击表名半天没反应、执行 sql 一直转圈、导出数据卡住、甚至整个连接变灰。这时候大概率不是 sql 慢,是表/行被锁住了,其他会话在等它释放。
实操建议:
- 在 Navicat 中右键数据库 →「命令列界面」,执行
SHOW PROCESSLIST;(MySQL)或SELECT * FROM pg_stat_activity WHERE state = 'active' OR wait_event_type = 'Lock';(PostgreSQL) - 重点找
Command列为Sleep但Time很大,或State显示Locked/idle in transaction (aborted)的行 - 若看到某条记录的
Info字段是UPDATE ... WHERE ...或BEGIN后长期没COMMIT,基本就是它
MySQL 中用 KILL 终止阻塞会话,但别乱杀
KILL 不是万能解药,杀错进程可能丢事务、丢数据,尤其生产环境必须谨慎。
实操建议:
- 先确认目标进程是否真在阻塞别人:执行
SELECT * FROM information_schema.INNODB_TRX\ ORDER BY trx_started DESC LIMIT 5;,看trx_mysql_thread_id和trx_state - 再查谁在等它:
SELECT * FROM information_schema.INNODB_LOCK_WAITS;(有结果就说明存在锁等待链) - 只对
trx_state = 'RUNNING'且明显异常(如运行超 300 秒、trx_query是未提交的 UPDATE)的线程执行KILL <code>thread_id; - 避免杀掉
system user或event_scheduler类型的后台线程
PostgreSQL 中 pg_terminate_backend 要配 oid 和 pid 两步走
PG 的锁定位比 MySQL 更依赖对象标识,直接用表名查不到锁,必须先转成 oid。
实操建议:
- 查表 oid:
SELECT oid FROM pg_class WHERE relname = '<code>your_table_name'; - 查锁住该表的 pid:
SELECT pid FROM pg_locks WHERE relation = <code>oid_from_aboveAND mode LIKE '%Exclusive%'; - 终止进程:
SELECT pg_terminate_backend(<code>pid);(注意:不能用字符串拼接,pid 是整数) - 如果只是想中断当前查询而非整个会话,用
SELECT pg_cancel_backend(<code>pid);
Navicat 自带的「查询分析器」能直接看到锁和慢查询共存场景
Navicat Monitor 或高版本 Navicat(16+)内置的「查询分析器」可以同时暴露锁 + 执行时间双维度问题,比手动查 processlist 更快定位复合瓶颈。
实操建议:
- 打开「查询分析器」→ 切换到「进程列表」页,按
Time倒序,找长时间Locked或Updating的行 - 点开某条慢查询详情,看「Blocking PID」字段——如果有值,说明它正被另一个 PID 阻塞
- 回到「前 5 个查询」页,对比「总时间」和「数量」:如果某条语句总时间高但次数少,很可能是被锁卡住;如果次数多且单次都慢,才是真慢查询
- 注意:查询分析器默认只读 performance_schema,需确保 MySQL 已开启
performance_schema=ON且用户有SELECT权限
真正麻烦的不是锁本身,是锁背后那个没提交的事务——它可能藏在应用代码里、藏在 Navicat 的某个未关闭的查询窗口中、甚至藏在另一个你忘了的终端 session 里。每次 kill 之后,务必顺手查一遍 INNODB_TRX 或 pg_stat_activity,确认没有残留的 idle in transaction。


















