如何通过SQL触发器监控表的大小变化_定期写入统计信息表

胖浩酱_2396

胖浩酱_2396

2026-05-11

792人浏览

原创

触发器不能直接获取表大小,只能作为变更信号触发后续统计;应避免在触发器中调用pg_total_relation_size()等重量级函数,而应通过标记表+定时任务方式获取真实大小。

如何通过sql触发器监控表的大小变化_定期写入统计信息表

触发器无法直接获取表大小,必须结合系统视图或外部工具

SQL 触发器(INSERT/UPDATE/DELETE)运行在 DML 语句执行期间,它能看到行级变更,但看不到物理存储变化——比如页分裂、索引重建、LOB 溢出等真正影响 pg_total_relation_size() 或 sys.dm_db_partition_stats 的因素。所以「监控表大小变化」不能靠触发器实时计算大小,而只能用它作为「变更信号」来触发后续统计动作。

常见错误是试图在触发器里写:SELECT pg_total_relation_size('my_table') 然后 INSERT 到日志表——这本身可行,但结果滞后且不准:事务未提交时大小未落盘;并发写入时多次采样可能重复或漏计;而且 PostgreSQL 中该函数会加轻量锁,高频触发易阻塞。

  • 正确做法:触发器只记录「发生了变更」,由独立调度任务(如 cron / pg_cron / SQL Server Agent)定期去查真实大小
  • 若坚持全链路由触发器驱动,需搭配 pg_stat_all_tables 的 n_tup_ins/n_tup_del 等累计计数,再辅以定时采样估算趋势
  • MySQL 用户注意:information_schema.TABLES 中的 data_length + index_length 是近似值,InnoDB 表可能滞后数秒到数分钟

PostgreSQL 示例:用 AFTER INSERT OR DELETE 触发器标记待统计表

核心思路是避免在触发器中做重量级查询,只写一行轻量标记。后续由 pg_cron 每 5 分钟扫描一次标记表,批量查真实大小并归档。

CREATE TABLE table_size_log (
  id SERIAL PRIMARY KEY,
  table_name TEXT NOT NULL,
  schema_name TEXT DEFAULT 'public',
  triggered_at TIMESTAMPTZ DEFAULT NOW(),
  size_bytes BIGINT,
  recorded_at TIMESTAMPTZ
);
<p>CREATE TABLE table_change_marker (
schema_name TEXT,
table_name TEXT,
marked_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (schema_name, table_name)
);</p><p>CREATE OR REPLACE FUNCTION mark_table_for_size_check()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO table_change_marker (schema_name, table_name)
VALUES (TG_TABLE_SCHEMA, TG_TABLE_NAME)
ON CONFLICT (schema_name, table_name) DO UPDATE
SET marked_at = EXCLUDED.marked_at;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;</p><p>CREATE TRIGGER trig_mark_user_changes
AFTER INSERT OR DELETE OR UPDATE ON users
FOR EACH STATEMENT EXECUTE FUNCTION mark_table_for_size_check();</p>

关键点:

  • AFTER ... FOR EACH STATEMENT 而非 FOR EACH ROW,避免高频写入时刷爆 table_change_marker
  • ON CONFLICT 确保同一张表短时间内多次变更只留最新标记
  • 不要在触发器里调用 pg_total_relation_size() —— 它会强制扫描所有块,对大表是灾难

SQL Server 中触发器调用 xp_cmdshell 查大小?别这么做

有人想在 AFTER INSERT 里跑 xp_cmdshell 调用 sqlcmd 查 sp_spaceused,这是严重设计错误。后果包括:

  • xp_cmdshell 默认禁用,开启需 sysadmin 权限,违反最小权限原则
  • 触发器内执行外部命令会极大拖慢事务响应,甚至导致死锁(尤其涉及 tempdb 或锁升级)
  • sp_spaceused 返回结果集,触发器无法直接消费,硬接会导致语法错误或静默失败

替代方案更稳:

1. 在触发器中仅插入一行到 dbo.size_audit_queue(含 object_id, queue_time);
2. 配置 SQL Server Agent 作业,每 2 分钟执行:
INSERT INTO dbo.size_history SELECT object_id, rows, reserved_page_count * 8192, GETDATE() FROM sys.dm_db_partition_stats WHERE object_id IN (SELECT object_id FROM dbo.size_audit_queue);
3. 清理已处理队列:DELETE FROM dbo.size_audit_queue WHERE queue_time

统计表结构设计要注意时间精度与分区裁剪

如果你的 table_size_log 表每天新增上万条,不加约束很快变慢。别只加个 created_at 索引就完事。

  • PostgreSQL:按 recorded_at 做范围分区(PARTITION BY RANGE (recorded_at)),每月一区,过期分区 DROP 比 DELETE 快百倍
  • SQL Server:用 datetime2(0) 而非 datetime,减少存储和比较开销;聚集索引建在 (schema_name, table_name, recorded_at) 上,方便按表查趋势
  • 字段别存「MB」或「GB」:统一用 BIGINT size_bytes,避免浮点误差和单位转换混乱

最常被忽略的是:没设 recorded_at 的默认值或没在应用层/调度脚本里显式赋值,导致大量 NULL,后续 GROUP BY 或 time_bucket 统计全乱套。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4523

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

931

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1189

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6481

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3263

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6440

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8821

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1190

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1052

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习