With times, old databases tend to overgrow with unnecessary or just empty fields. Whilst regular fields are not much of a concern, those with foreign key constraints, especially in tables with millions of records, would needlessly inflate the database file and put performance penalty on every insert/update/delete operation, as appropriate index need to be updated.
For example, an index on a field that holds nothing more than NULL values over a table with 100 000 000 records has a size approximately of 600 MB.
The query below helps to spot fields with foreign keys, which contain no more than a given count of unique values (by default, the variable maxuniqvalues is set to 1 to find all fields which are empty or contain exactly one value). Additionally, the condition on minimal record count in a table in question could be set through variable minreccnt.
The result data set includes the following columns: name of the relation, number of records in the relation, name of the field, value (only the first value is shown), and a list of objects dependent on the field. The latter will help a lot if the field to be deleted later.
EXECUTE BLOCK RETURNS( rn VARCHAR(31), reccnt INTEGER, fkfieldname VARCHAR(31), val INTEGER, dependent VARCHAR(8192) ) AS DECLARE VARIABLE minreccnt DOUBLE PRECISION = 1000000; DECLARE VARIABLE maxuniqvalues DOUBLE PRECISION = 1; BEGIN FOR SELECT rc.rdb$relation_name, CAST((1 / idx.rdb$statistics) AS INTEGER), idxsfk.rdb$field_name, (SELECT LIST(TRIM(d.rdb$dependent_name)) FROM rdb$dependencies d WHERE d.rdb$depended_on_name = rc.rdb$relation_name AND d.rdb$field_name = idxsfk.rdb$field_name) FROM rdb$relation_constraints rc JOIN rdb$indices idx ON idx.rdb$index_name = rc.rdb$index_name JOIN rdb$index_segments idxs ON idxs.rdb$index_name = idx.rdb$index_name AND idxs.rdb$field_position = 0 JOIN rdb$relation_constraints rcfk ON rcfk.rdb$constraint_type = 'FOREIGN KEY' AND rcfk.rdb$relation_name = rc.rdb$relation_name JOIN rdb$indices idxfk ON idxfk.rdb$index_name = rcfk.rdb$index_name JOIN rdb$index_segments idxsfk ON idxsfk.rdb$index_name = idxfk.rdb$index_name AND idxsfk.rdb$field_position = 0 WHERE rc.rdb$constraint_type = 'PRIMARY KEY' AND (idx.rdb$statistics > 0 AND idx.rdb$statistics < (1.0 / :minreccnt)) AND idxfk.rdb$statistics >= (1.0 / :maxuniqvalues) ORDER BY idx.rdb$statistics ASC INTO :rn, :reccnt, :fkfieldname, :dependent DO BEGIN EXECUTE STATEMENT 'SELECT FIRST 1 ' || :fkfieldname || ' FROM ' || :rn INTO :val; SUSPEND; END END