数据审计是一个跟踪表内容随时间变化的系统。数据审计是安全合规的必备功能之一。PostgreSQL作为一个强大的现代开源关系型数据库,还有一个相关的插件PGAudit可以提供审计功能。PGAudit插件可以在以后详细介绍。在本文中,我们介绍了一个通过简单的SQL语句实现的数据集审计功能。概述最终实现效果为:创建示例表:createextensionsupa_auditcascade;创建表public.account(idint主键,名称文本不为空);启用审计:selectaudit.enable_tracking('public.account'::regclass);增改删操作:insertintopublic.account(id,name)values(1,'冲冲');updatepublic.accountsetname='CC'whereid=1;deletefrompublic.accountwhereid=1;清空表:truncatetablepublic.account;查看审计日志:select*fromaudit.record_history注意更新一行时record_id和old_record_id保持不变,方便查询单行历史。要关闭审计跟踪,只需执行:selectaudit.disable_tracking('public.account'::regclass);实现首先创建一个名为audit的schema用于审计:createschemaifnotexistsaudit;记录存储接下来,您需要一个表来跟踪插入、更新和删除。传统上,审计模式与其他元数据列一起使用,例如提交的时间戳。该解决方案带来了一些维护挑战:对表启用审计需要数据库迁移当源表的模式发生变化时,被审计表的模式也必须改变为此,使用PostgreSQL的无模式JSONB数据类型来存储每条记录的数据在单列中间。这种方法的另一个好处是它允许将多个表的审计历史存储在单个审计表中。创建表audit.record_version(idbigserial主键,record_iduuid,old_record_iduuid,opvarchar(8)不为空,tstimestamptz不为空默认现在(),table_oidoid不为空,table_schema名称不为空,table_name名称不为空,记录jsonb,old_recordjsonb);查询和索引查询性能很重要,如果不能快速查询日志,审计日志的实际意义不大。为了提高查询性能,需要对最常用的查询涉及的字段创建索引。一个时间范围内的查询对于一个时间范围,需要一个索引ts。由于审计表只用于插入记录,而ts列插入的是操作时间,其值ts自然是按升序排列的。PostgreSQL内置的BRIN索引可以利用值和物理位置之间的相关性来生成一个比默认索引(BTREE索引)小数百倍并且具有更快查找时间的索引。使用brin(ts)创建索引record_version_tsonaudit.record_version;对于表查询,包括一个table_oid列,用于跟踪PostgreSQL内部数字表标识符。可以为该列而不是table_schema和able_name列添加索引,从而最小化索引大小并提供更好的性能。使用btree(table_oid)在audit.record_version上创建索引record_version_table_oid;记录唯一标识符将每一行的数据存储为jsonb的缺点之一是基于列值的过滤变得非常低效。如果您想快速查找一行的历史记录,您需要为每一行提取和索引一个唯一标识符。对于全局唯一标识符,使用以下结构:[table_oid,primary_key_value_1,primary_key_value_2,...]并将此数组散列为UUIDv5以获得有效的可索引UUID类型,以识别对数据更改具有鲁棒性的行。使用实用函数查找记录的主键列的名称:createorreplacefunctionaudit.primary_key_columns(entity_oidoid)returnstext[]stablesecuritydefinerlanguagesqlas$$--查找表的主键列的名称selectcoalesce(array_agg(pa.attname::textorderbypa.attnum),array[]::text[])column_namesfrompg_indexpijoinpg_attributepaonpi.indrelid=pa.attrelidandpa.attnum=any(pi.indkey)whereindrelid=$1andindisprimary$$;另一个对于table_oid和主键,将结果转换为记录的UUID。创建或替换函数audit.to_record_id(entity_oidoid,pkey_colstext[],recjsonb)返回uuidstablelanguagesqlas$$selectcasewhenrecisnullthennull--如果不存在主键,则使用随机uuidwhenpkey_cols=array[::text[]然后uuid_generate_v4()else(selectuuid_generate_v5('fd62bc3d-8d6e-43c2-919c-802ba3762271',(jsonb_build_array(to_jsonb($1))||jsonb_agg($3->key_)::text)fromunnest($2)x(键_))结束$$;最后,索引record_id和old_record_id包含这些用于快速查找的唯一标识符的列。创建索引record_version_record_idonaudit.record_version(record_id)其中record_id不为空;创建索引record_version_old_record_idonaudit.record_version(record_id)其中old_record_id不为空;触发器为使审计功能真正发挥作用,需要在最终用户未对其事务进行任何更改时执行此操作,以防向审计表中插入记录。为此,设置一个触发器以在数据更改时触发,并为每个插入/更新/删除操作触发一个触发器。创建或替换函数audit.insert_update_delete_trigger()返回triggersecuritydefinerlanguageplpgsqlas$$declarepkey_colstext[]=audit.primary_key_columns(TG_RELID);record_jsonbjsonb=to_jsonb(new);record_iduuid=audit.to_record_id(TG_RELID,pkey_cols,record_jsonb);old_record_jsonbjsonb=to_jsonb(old);old_record_iduuid=audit.to_record_id(TG_RELID,pkey_cols,old_record_jsonb);开始插入audit.record_version(record_id,old_record_id,op,table_oid,table_schema,table_name,record,old_record)selectrecord_id,old_record_id,TG_OP,TG_RELID,TG_TABLE_SCHEMA,TG_TABLE_NAME,record_jsonb,old_record_jsonb;返回合并(新,旧);结束;$$;API将公开用于在表上启用审计的API:selectaudit.enable_tracking('
- 1榨汁机实现品质和奢华,了解如何一步步选择榨汁机?
- 2可穿戴健身追踪器假日销售量实现飞跃
- 3丰田黑科技实现盲人驾驶梦想
- 4VAVA宠物机器人来了,实现远程互动、自动喂食
- 5搜狗文档翻译实现重要升级,支持日韩文档免费即时翻译
- 6O2O进入“下半场”,百度会利用AI实现弯道超车吗?
- 7融云小程序解决方案!业内率先实现商业落地
- 8极客智能家居!人口变化和现实环境需求将加速智能交通的实现
- 9要实现智能监控,首先要做好大数据存储
- 10长江商学院!从制造到智造,如何实现技术与商业结合?
- 11设计和生产可穿戴设备不是你想想就能实现的
- 12董明珠!格力空调将使用自家芯片,希望实现员工持股
- 13后Fitbit时代,中国可穿戴企业上市梦何时实现?
- 14让运维更智慧 以AI方式实现业务智能化运维
- 15观看 TA 的心跳 微软利用 HoloLens 实现远程生理
- 16VR能否帮助HTC实现逆袭?
- 17无人机农业距离实现成果还有多远?极飞推出植保机-培训-金融等
- 18450万的目标如何实现?看TCL洗冰机的“三大战役”
- 19虚拟现实版的互联网可能永远无法实现
- 20迪拜到2030年将实现25%自动驾驶