4 为分区准备审计日志表
概述
某些数据库(例如,MySQL)要求分区列必须是表的唯一约束的一部分。
因此,为了按时间对 auditlog 表进行分区,必须将主键从 auditid 更改为复合键 auditid + clock。
本节提供了更改 auditlog 表主键的说明。
本页提供的说明适用于高级用户。 请注意,这些说明可能需要根据您的特定配置进行调整。 修改主键可能与未来的升级补丁不兼容,因此可能需要手动处理未来的升级。
修改主键可能是一项资源消耗较大的操作,所需时间取决于 auditlog 表的大小。
建议在修改期间停止 Zabbix server 并将 Zabbix 前端切换到 maintenance mode。
但是,如果确实必要,也可以在不停机的情况下修改主键(见下文)。
对 auditlog 表进行分区可以改善例如在大型环境中的 housekeeping 操作。
尽管 Zabbix housekeeping 当前还无法利用分区表(TimescaleDB 除外),但您可以禁用 Zabbix 的 housekeeping 功能,并通过脚本管理 delete 分区。
自 Zabbix 7.0 开始,用于 TimescaleDB 的 auditlog 表已转换为 hypertable,这使得 housekeeper 可以按数据块来删除数据。
要将现有的 auditlog 表升级为 hypertable,请参阅 升级timescaledb架构。
MySQL
重建索引的重要说明
在 ALTER TABLE 操作期间,MySQL 会自动为主键重建索引。
不过,强烈建议同时使用 OPTIMIZE TABLE 语句手动重建索引,以确保数据库性能达到最佳。
重建索引时,临时所需的额外磁盘空间可能与表本身占用的空间一样多。
要获取数据和索引的当前大小,可以执行以下语句:
ANALYZE TABLE auditlog;
SHOW TABLE STATUS LIKE 'auditlog';
如果可用磁盘空间是一个问题,请按照在不停机的情况下更改主键中的说明进行操作。
还可以考虑以下其他选项:
- 增加 MySQL 参数
sort_buffer_size可能有助于在手动重建索引时减少磁盘空间使用。
但是,修改此变量可能会影响数据库的整体内存使用。 - 考虑通过删除可能不必要的数据来释放空间。
- 在执行 housekeeper 之前,考虑降低 数据存储周期 housekeeper 参数。
在停机期间更改主键
1. 删除当前 auditlog 表的主键,并添加新的主键。
ALTER TABLE auditlog DROP PRIMARY KEY, ADD PRIMARY KEY (auditid, clock);
2. 重建索引(可选,但强烈建议,参见 重建索引的重要说明)。
OPTIMIZE TABLE auditlog;
无停机更改主键
这里介绍了手动更改主键的方法。
或者,您也可以使用 Percona 的 pt-online-schema-change 工具包。
该工具包会自动执行以下操作,同时尽量减少更改 auditlog 表所需的空间。
1. 创建一个具有新主键的新表并创建索引。
CREATE TABLE `auditlog_new` (
`auditid` varchar(25) NOT NULL,
`userid` bigint unsigned NULL,
`username` varchar(100) DEFAULT '' NOT NULL,
`clock` integer DEFAULT '0' NOT NULL,
`ip` varchar(39) DEFAULT '' NOT NULL,
`action` integer DEFAULT '0' NOT NULL,
`resourcetype` integer DEFAULT '0' NOT NULL,
`resourceid` bigint unsigned NULL,
`resource_cuid` varchar(25) NULL,
`resourcename` varchar(255) DEFAULT '' NOT NULL,
`recordsetid` varchar(25) NOT NULL,
`details` longtext NOT NULL,
PRIMARY KEY (auditid,clock)
) ENGINE=InnoDB;
CREATE INDEX `auditlog_1` ON `auditlog_new` (`userid`,`clock`);
CREATE INDEX `auditlog_2` ON `auditlog_new` (`clock`);
CREATE INDEX `auditlog_3` ON `auditlog_new` (`resourcetype`,`resourceid`);
2. 交换表。
RENAME TABLE auditlog TO auditlog_old, auditlog_new TO auditlog;
3. 将数据从旧表复制到新表。
INSERT INTO auditlog SELECT * FROM auditlog_old;
可以分批执行(根据需要使用带有 WHERE clock 子句的多个 INSERT INTO 语句),以避免过度消耗资源。
4. 删除旧表。
DROP TABLE auditlog_old;
PostgreSQL
重建索引的重要说明
在执行 ALTER TABLE 操作期间,PostgreSQL 会自动为主键重建索引。
不过,强烈建议同时使用 REINDEX TABLE CONCURRENTLY 语句手动重建索引,以确保数据库性能达到最佳状态。
重建索引时,临时所需的磁盘空间最多可能达到当前索引占用空间的三倍。 要获取索引的当前大小,可以执行以下查询:
SELECT pg_size_pretty(pg_indexes_size('auditlog'));
如果可用磁盘空间有限,请按照无需停机更改主键中的说明进行操作。 此外,还可以考虑以下选项:
- 增加 PostgreSQL 参数
maintenance_work_mem的值,可能有助于在手动重建索引时减少磁盘空间使用。 不过,修改此变量可能会影响数据库的整体内存使用。 - 如果您有另一块磁盘或一个可用空间更多的表空间,可以考虑更改索引重建时的临时存储位置。
您可以设置 PostgreSQL 参数
temp_tablespaces,为临时对象指定其他表空间。 - 考虑通过删除可能不必要的数据来释放空间。
- 在执行 housekeeper 之前,考虑降低 数据存储周期 housekeeper 参数。
修改主键并停机
1. 删除当前 auditlog 表的主键,并添加新的主键。
ALTER TABLE auditlog DROP CONSTRAINT auditlog_pkey;
ALTER TABLE auditlog ADD PRIMARY KEY (auditid,clock);
2. 重建索引(可选,但强烈建议,参见重建索引的重要说明)。
REINDEX TABLE CONCURRENTLY auditlog;
无停机更改主键
这里介绍了手动更改主键的方法。
另外,也可以考虑使用 pg_repack 扩展来创建新表、复制数据并交换表。
1. 创建一个具有新主键的新表并创建索引。
CREATE TABLE auditlog_new (
auditid varchar(25) NOT NULL,
userid bigint NULL,
username varchar(100) DEFAULT '' NOT NULL,
clock integer DEFAULT '0' NOT NULL,
ip varchar(39) DEFAULT '' NOT NULL,
action integer DEFAULT '0' NOT NULL,
resourcetype integer DEFAULT '0' NOT NULL,
resourceid bigint NULL,
resource_cuid varchar(25) NULL,
resourcename varchar(255) DEFAULT '' NOT NULL,
recordsetid varchar(25) NOT NULL,
details text DEFAULT '' NOT NULL,
PRIMARY KEY (auditid,clock)
);
CREATE INDEX auditlog_new_1 ON auditlog_new (userid,clock);
CREATE INDEX auditlog_new_2 ON auditlog_new (clock);
CREATE INDEX auditlog_new_3 ON auditlog_new (resourcetype,resourceid);
2. 交换表。
ALTER TABLE auditlog RENAME TO auditlog_old;
ALTER TABLE auditlog_new RENAME TO auditlog;
3. 将数据从旧表复制到新表。
INSERT INTO auditlog SELECT * FROM auditlog_old;
可以分批执行(根据需要使用多个带有 WHERE clock 子句的 INSERT INTO 语句),以避免过度消耗资源。
4. 删除旧表。
DROP TABLE auditlog_old;
Oracle
重建索引的重要说明
在执行 ALTER TABLE 操作期间,Oracle 会自动重建主键的索引。
不过,强烈建议同时使用 ALTER INDEX <index> REBUILD PARALLEL 语句手动重建索引,以确保数据库性能达到最佳状态。
重建索引可能会在短时间内需要大量磁盘空间。
如果可用磁盘空间是一个问题,请参阅无停机时间修改主键中的说明。
还可以使用以下其他选项:
- 增加 Oracle 参数
SORT_AREA_SIZE可能有助于在手动重建索引时减少磁盘空间使用。
但是,修改此变量会影响数据库的整体内存使用量。 - 您可以使用 PARALLEL 子句设置并行度,例如:
ALTER INDEX auditlog_1 REBUILD PARALLEL 4 - 考虑通过删除可能不必要的数据来释放空间。
- 在执行 housekeeper 之前,考虑降低 Data storage period housekeeper 参数。
在停机期间更改主键
1. 获取约束名称。
SELECT CONSTRAINT_NAME FROM all_constraints WHERE TABLE_NAME = 'AUDITLOG' AND CONSTRAINT_TYPE = 'P';
2. 删除当前 auditlog 表的主键,并添加新的主键。
ALTER TABLE auditlog DROP CONSTRAINT <constraint_name>;
ALTER TABLE auditlog ADD CONSTRAINT auditlog_pk PRIMARY KEY (auditid, clock);
3. 重建索引(可选,但强烈建议,参见重建索引的重要说明)。
3.1. 获取索引名称。
SELECT index_name FROM user_indexes WHERE table_name='AUDITLOG';
3.2. 重建每个索引。
ALTER INDEX auditlog_pk REBUILD PARALLEL;
ALTER INDEX auditlog_1 REBUILD PARALLEL;
ALTER INDEX auditlog_2 REBUILD PARALLEL;
ALTER INDEX auditlog_3 REBUILD PARALLEL;
无停机更改主键
1. 创建一个具有新主键的新表,并创建索引。
CREATE TABLE auditlog_new (
auditid nvarchar2(25) ,
userid number(20) NULL,
username nvarchar2(100) DEFAULT '' ,
clock number(10) DEFAULT '0' NOT NULL,
ip nvarchar2(39) DEFAULT '' ,
action number(10) DEFAULT '0' NOT NULL,
resourcetype number(10) DEFAULT '0' NOT NULL,
resourceid number(20) NULL,
resource_cuid nvarchar2(25) ,
resourcename nvarchar2(255) DEFAULT '' ,
recordsetid nvarchar2(25) ,
details nclob DEFAULT '' ,
PRIMARY KEY (auditid,clock)
);
CREATE INDEX auditlog_new_1 ON auditlog_new (userid,clock);
CREATE INDEX auditlog_new_2 ON auditlog_new (clock);
CREATE INDEX auditlog_new_3 ON auditlog_new (resourcetype,resourceid);
2. 交换表。
ALTER TABLE auditlog RENAME TO auditlog_old;
ALTER TABLE auditlog_new RENAME TO auditlog;
3. 将数据从旧表复制到新表。
INSERT INTO auditlog SELECT * FROM auditlog_old;
可以分批执行(根据需要使用多个 INSERT INTO 语句并配合 WHERE clock 子句),以避免过度消耗资源。
4. 删除旧表。
DROP TABLE auditlog_old;