需要监控数据库的序列,在达到最大值前,进行告警。特别是mysql,往往因为字段的定义和auto incremental的定义不同,导致各自的上限不同。
Oracle:
SELECT x.*, CASE WHEN increment_by<0 THEN round(last_number/min_value*100,4) WHEN increment_by>0 THEN round(last_number/max_value*100,4) ELSE 0 END AS percent_usage from DBA_SEQUENCES x WHERE cycle_flag='N' ORDER BY percent_usage DESC;
SQL Server:
SELECT max( CASE WHEN increment_by<0 THEN round(last_number/min_value*100,4) WHEN increment_by>0 THEN round(last_number/max_value*100,4) ELSE 0 END ) AS percent_usage from DBA_SEQUENCES x WHERE cycle_flag='N' ORDER BY percent_usage DESC;
pg:
--(1)初始化部署: --(1.1)数据库内部署表和函数(注,如果一个pg实例中有多个数据库需要监控,需要部署到多个库): drop table oracleblog_pg_sequence; create table oracleblog_pg_sequence ( record_time timestamp with time zone, sequence_name TEXT , last_value bigint , start_value bigint , increment_by bigint , max_value bigint , min_value bigint , cache_value bigint , log_cnt bigint , is_cycled boolean, is_called boolean, sequence_schema TEXT, table_name text, column_name TEXT, data_type text, datatype_maxval bigint, datatype_minval bigint, cap_value bigint ); DROP function oracleblog_get_seqval(); CREATE OR REPLACE FUNCTION oracleblog_get_seqval() RETURNS void AS $sequence_values$ DECLARE nsp_name TEXT; seq_name TEXT; BEGIN EXECUTE 'truncate table oracleblog_pg_sequence'; FOR nsp_name, seq_name IN SELECT nspname::text, relname::text FROM pg_class JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid WHERE relkind='S' LOOP EXECUTE 'INSERT into oracleblog_pg_sequence(sequence_name,last_value,start_value,increment_by,max_value,min_value,cache_value,log_cnt,is_cycled,is_called,sequence_schema) SELECT x.*,' || '''' || nsp_name || '''' ||' from ' || nsp_name ||'.' ||seq_name ||' x'; END LOOP; update oracleblog_pg_sequence a set table_name=(select table_name from INFORMATION_SCHEMA.COLUMNS b where SPLIT_PART(COLUMN_DEFAULT, '''', 2) = SEQUENCE_NAME and sequence_schema=table_schema), column_name=(select column_name from INFORMATION_SCHEMA.COLUMNS b where SPLIT_PART(COLUMN_DEFAULT, '''', 2) = SEQUENCE_NAME and sequence_schema=table_schema), data_type=(select data_type from INFORMATION_SCHEMA.COLUMNS b where SPLIT_PART(COLUMN_DEFAULT, '''', 2) = SEQUENCE_NAME and sequence_schema=table_schema), datatype_maxval=(select CASE lower(DATA_TYPE) when 'smallint' then 32767 when 'integer' then 2147483647 when 'serial' then 2147483647 when 'bigint' then 9223372036854775807 when 'bigserial' then 9223372036854775807 else null end from INFORMATION_SCHEMA.COLUMNS b where SPLIT_PART(COLUMN_DEFAULT, '''', 2) = SEQUENCE_NAME and sequence_schema=table_schema), datatype_minval=(select CASE lower(DATA_TYPE) when 'smallint' then -32767 when 'integer' then -2147483647 when 'serial' then 1 when 'bigint' then -9223372036854775807 when 'bigserial' then 1 else null end from INFORMATION_SCHEMA.COLUMNS b where SPLIT_PART(COLUMN_DEFAULT, '''', 2) = SEQUENCE_NAME and sequence_schema=table_schema); update oracleblog_pg_sequence set cap_value=( case when INCREMENT_BY < 0 then (case when min_value>=datatype_minval then min_value when min_value<=datatype_minval then datatype_minval end) when INCREMENT_BY > 0 then (case when max_value>=datatype_maxval then datatype_maxval when max_value<=datatype_maxval then max_value end) end), record_time=now() ; END; $sequence_values$ LANGUAGE plpgsql; --(1.2)在没有安装pgAgent的环境下,用crontab实现定时刷新(注,如果一个pg实例中有多个数据库需要监控,需要部署多个crontab,每个crontab的-d参数后跟不同的库): cat /data001/PRD/postgres/9.6.2/home/postgres/crontab_script/fresh_oracleblog_pg_sequence.sh #!/bin/bash /data/PRD/postgres/base/9.6.2/bin/psql -d dbinfo -c "select oracleblog_get_seqval()" chmod +x /data001/PRD/postgres/9.6.2/home/postgres/crontab_script/fresh_oracleblog_pg_sequence.sh crontab -l 01 * * * * /bin/bash /data001/PRD/postgres/9.6.2/home/postgres/crontab_script/fresh_oracleblog_pg_sequence.sh --(2)给zabbix用户授权: grant select on oracleblog_pg_sequence to zabbix; --(3)查询结果: --(3.1)用于监控语句: select max(round((1-(cap_value-last_value)::numeric/(cap_value-start_value)::numeric)*100,4)) as max_usage_percent from oracleblog_pg_sequence where is_cycled='f'; --(3.2)平时运维检查: select SEQUENCE_NAME, last_value, start_value, increment_by, cap_value, round((1-(cap_value-last_value)::numeric/(cap_value-start_value)::numeric)*100,4) as usage_percent from oracleblog_pg_sequence where is_cycled='f' order by usage_percent desc;
MySQL:
CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_awr_getauto_increment_status`() BEGIN TRUNCATE TABLE myawr.auto_increment_status; INSERT INTO myawr.auto_increment_status (clock, table_schema, table_name,auto_increment_increment,auto_increment_offset,auto_increment_max,auto_increment_used) SELECT now() AS clock, b.table_schema, b.table_name ,(select VARIABLE_VALUE from performance_schema.global_variables where VARIABLE_NAME = 'auto_increment_increment') as auto_increment_increment ,(select VARIABLE_VALUE from performance_schema.global_variables where VARIABLE_NAME = 'auto_increment_offset') as auto_increment_offset , CASE WHEN COLUMN_TYPE LIKE 'bigint%' THEN 9223372036854775808 WHEN COLUMN_TYPE LIKE 'int(%)' THEN 2147483647 WHEN COLUMN_TYPE LIKE 'int(%) unsigned' THEN 4294967295 WHEN COLUMN_TYPE LIKE 'MEDIUMINT(%)' THEN 8388607 WHEN COLUMN_TYPE LIKE 'MEDIUMINT(%) unsigned' THEN 16777215 WHEN COLUMN_TYPE LIKE 'SMALLINT(%)' THEN 32767 WHEN COLUMN_TYPE LIKE 'SMALLINT(%) unsigned' THEN 65535 WHEN COLUMN_TYPE LIKE 'TINYINT(%)' THEN 127 WHEN COLUMN_TYPE LIKE 'TINYINT(%) unsigned' THEN 255 ELSE 'other' END AS auto_increment_max , CASE WHEN COLUMN_TYPE LIKE 'bigint%' THEN format(b.auto_increment / 9223372036854775808 * 100, 0) WHEN COLUMN_TYPE LIKE 'int(%)' THEN format(b.auto_increment / 2147483647 * 100, 0) WHEN COLUMN_TYPE LIKE 'int(%) unsigned' THEN format(b.auto_increment / 4294967295 * 100, 0) WHEN COLUMN_TYPE LIKE 'MEDIUMINT(%)' THEN format(b.auto_increment / 8388607 * 100, 0) WHEN COLUMN_TYPE LIKE 'MEDIUMINT(%) unsigned' THEN format(b.auto_increment / 16777215 * 100, 0) WHEN COLUMN_TYPE LIKE 'SMALLINT(%)' THEN format(b.auto_increment / 32767 * 100, 0) WHEN COLUMN_TYPE LIKE 'SMALLINT(%) unsigned' THEN format(b.auto_increment / 65535 * 100, 0) WHEN COLUMN_TYPE LIKE 'TINYINT(%)' THEN format(b.auto_increment / 127 * 100, 0) WHEN COLUMN_TYPE LIKE 'TINYINT(%) unsigned' THEN format(b.auto_increment / 255 * 100, 0) ELSE '100' END AS auto_increment_used FROM information_schema.columns a JOIN information_schema.tables b ON a.table_name = b.table_name AND a.table_schema = b.table_schema WHERE EXTRA = 'auto_increment' ORDER BY auto_increment_used + 0 DESC LIMIT 10; CREATE DEFINER=`root`@`localhost` EVENT `event_awr_getauto_increment_status` ON SCHEDULE EVERY 1 HOUR STARTS '2019-04-17 11:45:34' ON COMPLETION PRESERVE ENABLE DO call myawr.proc_awr_getauto_increment_status()