Findings
Errors (39)
Junction table allows duplicate links
agent_organization_authorizations looks like a many-to-many link table but has no unique constraint across (agent_id, organization_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE agent_organization_authorizations ADD PRIMARY KEY (agent_id, organization_id);
Junction table allows duplicate links
analytics_cycle_analytics_value_stream_settings looks like a many-to-many link table but has no unique constraint across (namespace_id, value_stream_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE analytics_cycle_analytics_value_stream_settings ADD PRIMARY KEY (namespace_id, value_stream_id);
Monetary value stored as float
namespace_storage_forks_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE application_settings ALTER COLUMN namespace_storage_forks_cost_factor TYPE numeric(14,2);
Monetary value stored as float
sentry_clientside_traces_sample_rate is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE application_settings ALTER COLUMN sentry_clientside_traces_sample_rate TYPE numeric(14,2);
Junction table allows duplicate links
audit_events_streaming_http_group_namespace_filters looks like a many-to-many link table but has no unique constraint across (external_audit_event_destination_id, namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE audit_events_streaming_http_group_namespace_filters ADD PRIMARY KEY (external_audit_event_destination_id, namespace_id);
Junction table allows duplicate links
audit_events_streaming_http_instance_namespace_filters looks like a many-to-many link table but has no unique constraint across (audit_events_instance_external_audit_event_destination_id, namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE audit_events_streaming_http_instance_namespace_filters ADD PRIMARY KEY (audit_events_instance_external_audit_event_destination_id, namespace_id);
F1348ci_runners public_projects_minutes_cost_factormoney-float Monetary value stored as float
public_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE ci_runners ALTER COLUMN public_projects_minutes_cost_factor TYPE numeric(14,2);
F1349ci_runners private_projects_minutes_cost_factormoney-float Monetary value stored as float
private_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE ci_runners ALTER COLUMN private_projects_minutes_cost_factor TYPE numeric(14,2);
Junction table allows duplicate links
cluster_projects looks like a many-to-many link table but has no unique constraint across (cluster_id, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE cluster_projects ADD PRIMARY KEY (cluster_id, project_id);
Junction table allows duplicate links
csv_issue_imports looks like a many-to-many link table but has no unique constraint across (project_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE csv_issue_imports ADD PRIMARY KEY (project_id, user_id);
Junction table allows duplicate links
duo_workflows_workloads looks like a many-to-many link table but has no unique constraint across (project_id, workflow_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE duo_workflows_workloads ADD PRIMARY KEY (project_id, workflow_id);
Junction table allows duplicate links
group_deletion_schedules looks like a many-to-many link table but has no unique constraint across (group_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE group_deletion_schedules ADD PRIMARY KEY (group_id, user_id);
Monetary value stored as float
public_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE group_type_ci_runners ALTER COLUMN public_projects_minutes_cost_factor TYPE numeric(14,2);
Monetary value stored as float
private_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE group_type_ci_runners ALTER COLUMN private_projects_minutes_cost_factor TYPE numeric(14,2);
F795insights namespace_id, project_idjunction-uniqueness Junction table allows duplicate links
insights looks like a many-to-many link table but has no unique constraint across (namespace_id, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE insights ADD PRIMARY KEY (namespace_id, project_id);
Monetary value stored as float
public_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE instance_type_ci_runners ALTER COLUMN public_projects_minutes_cost_factor TYPE numeric(14,2);
Monetary value stored as float
private_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE instance_type_ci_runners ALTER COLUMN private_projects_minutes_cost_factor TYPE numeric(14,2);
Junction table allows duplicate links
lfs_file_locks looks like a many-to-many link table but has no unique constraint across (project_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE lfs_file_locks ADD PRIMARY KEY (project_id, user_id);
Junction table allows duplicate links
merge_request_merge_schedules looks like a many-to-many link table but has no unique constraint across (merge_request_id, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE merge_request_merge_schedules ADD PRIMARY KEY (merge_request_id, project_id);
Junction table allows duplicate links
namespace_import_users looks like a many-to-many link table but has no unique constraint across (namespace_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE namespace_import_users ADD PRIMARY KEY (namespace_id, user_id);
Junction table allows duplicate links
namespace_secret_counts looks like a many-to-many link table but has no unique constraint across (namespace_id, root_namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE namespace_secret_counts ADD PRIMARY KEY (namespace_id, root_namespace_id);
Junction table allows duplicate links
oauth_openid_requests looks like a many-to-many link table but has no unique constraint across (access_grant_id, organization_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE oauth_openid_requests ADD PRIMARY KEY (access_grant_id, organization_id);
Junction table allows duplicate links
observability_traces_issues_connections looks like a many-to-many link table but has no unique constraint across (issue_id, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE observability_traces_issues_connections ADD PRIMARY KEY (issue_id, project_id);
Junction table allows duplicate links
p_ci_job_definition_instances looks like a many-to-many link table but has no unique constraint across (job_definition_id, job_id, partition_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE p_ci_job_definition_instances ADD PRIMARY KEY (job_definition_id, job_id, partition_id);
Junction table allows duplicate links
p_generated_ref_commits looks like a many-to-many link table but has no unique constraint across (merge_request_iid, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE p_generated_ref_commits ADD PRIMARY KEY (merge_request_iid, project_id);
Junction table allows duplicate links
packages_pypi_file_metadata looks like a many-to-many link table but has no unique constraint across (package_file_id, project_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE packages_pypi_file_metadata ADD PRIMARY KEY (package_file_id, project_id);
Junction table allows duplicate links
personal_access_token_last_used_ips looks like a many-to-many link table but has no unique constraint across (organization_id, personal_access_token_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE personal_access_token_last_used_ips ADD PRIMARY KEY (organization_id, personal_access_token_id);
Monetary value stored as float
public_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE project_type_ci_runners ALTER COLUMN public_projects_minutes_cost_factor TYPE numeric(14,2);
Monetary value stored as float
private_projects_minutes_cost_factor is binary floating point. 0.1 + 0.2 ≠ 0.3; sums drift; reconciliation against the ledger will be off by cents.
Fix Use NUMERIC(p, s) or integer minor units.
ALTER TABLE project_type_ci_runners ALTER COLUMN private_projects_minutes_cost_factor TYPE numeric(14,2);
Junction table allows duplicate links
projects_branch_rules_squash_options looks like a many-to-many link table but has no unique constraint across (project_id, protected_branch_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE projects_branch_rules_squash_options ADD PRIMARY KEY (project_id, protected_branch_id);
Junction table allows duplicate links
security_policy_schedule_pipelines looks like a many-to-many link table but has no unique constraint across (project_id, security_policy_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE security_policy_schedule_pipelines ADD PRIMARY KEY (project_id, security_policy_id);
Junction table allows duplicate links
user_admin_roles looks like a many-to-many link table but has no unique constraint across (admin_role_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE user_admin_roles ADD PRIMARY KEY (admin_role_id, user_id);
Junction table allows duplicate links
user_member_roles looks like a many-to-many link table but has no unique constraint across (member_role_id, user_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE user_member_roles ADD PRIMARY KEY (member_role_id, user_id);
Junction table allows duplicate links
vulnerability_finding_ascp_component_links looks like a many-to-many link table but has no unique constraint across (ascp_component_id, vulnerability_occurrence_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE vulnerability_finding_ascp_component_links ADD PRIMARY KEY (ascp_component_id, vulnerability_occurrence_id);
Junction table allows duplicate links
work_item_colors looks like a many-to-many link table but has no unique constraint across (issue_id, namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE work_item_colors ADD PRIMARY KEY (issue_id, namespace_id);
Junction table allows duplicate links
work_item_type_custom_lifecycles looks like a many-to-many link table but has no unique constraint across (lifecycle_id, namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE work_item_type_custom_lifecycles ADD PRIMARY KEY (lifecycle_id, namespace_id);
Junction table allows duplicate links
workspace_agentk_states looks like a many-to-many link table but has no unique constraint across (project_id, workspace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE workspace_agentk_states ADD PRIMARY KEY (project_id, workspace_id);
Junction table allows duplicate links
workspace_tokens looks like a many-to-many link table but has no unique constraint across (project_id, workspace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE workspace_tokens ADD PRIMARY KEY (project_id, workspace_id);
F813zoekt_replicas namespace_id, zoekt_enabled_namespace_idjunction-uniqueness Junction table allows duplicate links
zoekt_replicas looks like a many-to-many link table but has no unique constraint across (namespace_id, zoekt_enabled_namespace_id). The same pair can be inserted twice; every join through it will double-count.
Fix Use the FK pair as the primary key (or add a UNIQUE).
ALTER TABLE zoekt_replicas ADD PRIMARY KEY (namespace_id, zoekt_enabled_namespace_id);
Warnings (161)
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE abuse_report_uploads ADD CONSTRAINT abuse_report_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE achievement_uploads ADD CONSTRAINT achievement_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Foreign-key cycle
ai_catalog_item_versions → ai_catalog_items → ai_catalog_item_versions. Rows must be inserted with a deferred constraint or a NULL-then-update dance; backups/restores and truncation have no valid order; ON DELETE CASCADE can loop.
Fix Break the cycle (move one FK to a link table) or mark one FK DEFERRABLE INITIALLY DEFERRED.
Soft delete collides with non-partial UNIQUE
ai_catalog_items soft-deletes via deleted_at, but (organization_id, identifier, item_type) is unique across live AND deleted rows. A user who deletes their account can never sign up again with the same value, and ON CONFLICT upserts will resurrect ghosts.
Fix Replace with a partial unique index scoped to live rows.
DROP CONSTRAINT/INDEX ...; CREATE UNIQUE INDEX ai_catalog_items_organization_id_identifier_item_type_live ON ai_catalog_items(organization_id, identifier, item_type) WHERE deleted_at IS NULL;
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE ai_vectorizable_file_uploads ADD CONSTRAINT ai_vectorizable_file_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE alert_management_alert_metric_image_uploads ADD CONSTRAINT alert_management_alert_metric_image_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE appearance_uploads ADD CONSTRAINT appearance_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
entity_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE audit_events ADD CONSTRAINT audit_events_entity_type_check CHECK (entity_type IN (...));
F891audit_events entity_type, entity_idpolymorphic-reference Polymorphic reference without referential integrity
entity_id points at different tables depending on entity_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F892audit_events target_type, target_idpolymorphic-reference Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
awardable_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE award_emoji ADD CONSTRAINT award_emoji_awardable_type_check CHECK (awardable_type IN (...));
F904award_emoji awardable_type, awardable_idpolymorphic-reference Polymorphic reference without referential integrity
awardable_id points at different tables depending on awardable_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F832badges typeundocumented-enum Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE badges ADD CONSTRAINT badges_type_check CHECK (type IN (...));
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE bulk_import_export_upload_uploads ADD CONSTRAINT bulk_import_export_upload_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan ci_build_trace_chunks to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_build_trace_chunks maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_build_trace_chunks_partition_id_build_id ON ci_build_trace_chunks(partition_id, build_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_daily_build_group_report_results to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_daily_build_group_report_results maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_daily_build_group_report_results_partition_id_last_pipeline_id ON ci_daily_build_group_report_results(partition_id, last_pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan ci_job_variables to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_job_variables maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_job_variables_partition_id_job_id ON ci_job_variables(partition_id, job_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_pipeline_artifacts to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_pipeline_artifacts maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_pipeline_artifacts_partition_id_pipeline_id ON ci_pipeline_artifacts(partition_id, pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_pipeline_chat_data to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_pipeline_chat_data maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_pipeline_chat_data_partition_id_pipeline_id ON ci_pipeline_chat_data(partition_id, pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_pipeline_messages to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_pipeline_messages maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_pipeline_messages_partition_id_pipeline_id ON ci_pipeline_messages(partition_id, pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_pipeline_metadata to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_pipeline_metadata maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_pipeline_metadata_partition_id_pipeline_id ON ci_pipeline_metadata(partition_id, pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan ci_resources to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_resources maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, build_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_ci_resources_partition_id_build_id ON ci_resources(partition_id, build_id) WHERE partition_id IS NOT NULL AND build_id IS NOT NULL;
Polymorphic reference without referential integrity
runner_id points at different tables depending on runner_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Polymorphic reference without referential integrity
runner_id points at different tables depending on runner_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Polymorphic reference without referential integrity
runner_id points at different tables depending on runner_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Polymorphic reference without referential integrity
runner_id points at different tables depending on runner_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan ci_sources_pipelines to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_sources_pipelines maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. source_partition_id, source_job_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_ci_sources_pipelines_source_partition_id_source_job_id ON ci_sources_pipelines(source_partition_id, source_job_id) WHERE source_partition_id IS NOT NULL AND source_job_id IS NOT NULL;
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_sources_pipelines to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_sources_pipelines maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. source_partition_id, source_pipeline_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_ci_sources_pipelines_source_partition_id_source_pipeline_id ON ci_sources_pipelines(source_partition_id, source_pipeline_id) WHERE source_partition_id IS NOT NULL AND source_pipeline_id IS NOT NULL;
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_sources_pipelines to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_sources_pipelines maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, pipeline_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_ci_sources_pipelines_partition_id_pipeline_id ON ci_sources_pipelines(partition_id, pipeline_id) WHERE partition_id IS NOT NULL AND pipeline_id IS NOT NULL;
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan ci_sources_projects to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_sources_projects maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_sources_projects_partition_id_pipeline_id ON ci_sources_projects(partition_id, pipeline_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan ci_unit_test_failures to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to ci_unit_test_failures maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_ci_unit_test_failures_partition_id_build_id ON ci_unit_test_failures(partition_id, build_id);
Enum-like column with no CHECK
environment_scope is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE ci_variables ADD CONSTRAINT ci_variables_environment_scope_check CHECK (environment_scope IN (...));
Enum-like column with no CHECK
machine_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE cluster_providers_gcp ADD CONSTRAINT cluster_providers_gcp_machine_type_check CHECK (machine_type IN (...));
F836clusters environment_scopeundocumented-enum Enum-like column with no CHECK
environment_scope is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE clusters ADD CONSTRAINT clusters_environment_scope_check CHECK (environment_scope IN (...));
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE dependency_list_export_part_uploads ADD CONSTRAINT dependency_list_export_part_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE dependency_list_export_uploads ADD CONSTRAINT dependency_list_export_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
deployable_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE deployments ADD CONSTRAINT deployments_deployable_type_check CHECK (deployable_type IN (...));
F912deployments deployable_type, deployable_idpolymorphic-reference Polymorphic reference without referential integrity
deployable_id points at different tables depending on deployable_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE design_management_action_uploads ADD CONSTRAINT design_management_action_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
environment_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE environments ADD CONSTRAINT environments_environment_type_check CHECK (environment_type IN (...));
Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE environments ADD CONSTRAINT environments_state_check CHECK (state IN (...));
F843events target_typeundocumented-enum Enum-like column with no CHECK
target_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE events ADD CONSTRAINT events_target_type_check CHECK (target_type IN (...));
F914events target_type, target_idpolymorphic-reference Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F844geo_nodes selective_sync_typeundocumented-enum Enum-like column with no CHECK
selective_sync_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE geo_nodes ADD CONSTRAINT geo_nodes_selective_sync_type_check CHECK (selective_sync_type IN (...));
Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F916iam_outbox entity_type, entity_idpolymorphic-reference Polymorphic reference without referential integrity
entity_id points at different tables depending on entity_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE import_export_upload_uploads ADD CONSTRAINT import_export_upload_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
category is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE integrations ADD CONSTRAINT integrations_category_check CHECK (category IN (...));
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE issuable_metric_image_uploads ADD CONSTRAINT issuable_metric_image_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Foreign-key cycle
issues → epics → work_item_parent_links → issues. Rows must be inserted with a deferred constraint or a NULL-then-update dance; backups/restores and truncation have no valid order; ON DELETE CASCADE can loop.
Fix Break the cycle (move one FK to a link table) or mark one FK DEFERRABLE INITIALLY DEFERRED.
Foreign-key cycle
issues → epics → issues. Rows must be inserted with a deferred constraint or a NULL-then-update dance; backups/restores and truncation have no valid order; ON DELETE CASCADE can loop.
Fix Break the cycle (move one FK to a link table) or mark one FK DEFERRABLE INITIALLY DEFERRED.
F849keys typeundocumented-enum Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE keys ADD CONSTRAINT keys_type_check CHECK (type IN (...));
Enum-like column with no CHECK
target_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE label_links ADD CONSTRAINT label_links_target_type_check CHECK (target_type IN (...));
F919label_links target_type, target_idpolymorphic-reference Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F851labels typeundocumented-enum Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE labels ADD CONSTRAINT labels_type_check CHECK (type IN (...));
F852members source_typeundocumented-enum Enum-like column with no CHECK
source_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE members ADD CONSTRAINT members_source_type_check CHECK (source_type IN (...));
Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE members ADD CONSTRAINT members_type_check CHECK (type IN (...));
F920members source_type, source_idpolymorphic-reference Polymorphic reference without referential integrity
source_id points at different tables depending on source_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
a_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_request_diff_files ADD CONSTRAINT merge_request_diff_files_a_mode_check CHECK (a_mode IN (...));
Enum-like column with no CHECK
b_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_request_diff_files ADD CONSTRAINT merge_request_diff_files_b_mode_check CHECK (b_mode IN (...));
Enum-like column with no CHECK
a_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_request_diff_files_99208b8fac ADD CONSTRAINT merge_request_diff_files_99208b8fac_a_mode_check CHECK (a_mode IN (...));
Enum-like column with no CHECK
b_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_request_diff_files_99208b8fac ADD CONSTRAINT merge_request_diff_files_99208b8fac_b_mode_check CHECK (b_mode IN (...));
Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_request_diffs ADD CONSTRAINT merge_request_diffs_state_check CHECK (state IN (...));
Foreign-key cycle
merge_requests → merge_request_diffs → merge_requests. Rows must be inserted with a deferred constraint or a NULL-then-update dance; backups/restores and truncation have no valid order; ON DELETE CASCADE can loop.
Fix Break the cycle (move one FK to a link table) or mark one FK DEFERRABLE INITIALLY DEFERRED.
Enum-like column with no CHECK
merge_status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE merge_requests ADD CONSTRAINT merge_requests_merge_status_check CHECK (merge_status IN (...));
Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE milestones ADD CONSTRAINT milestones_state_check CHECK (state IN (...));
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE namespace_uploads ADD CONSTRAINT namespace_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE namespaces ADD CONSTRAINT namespaces_type_check CHECK (type IN (...));
Enum-like column with no CHECK
ldap_sync_status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE namespaces ADD CONSTRAINT namespaces_ldap_sync_status_check CHECK (ldap_sync_status IN (...));
Enum-like column with no CHECK
a_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE note_diff_files ADD CONSTRAINT note_diff_files_a_mode_check CHECK (a_mode IN (...));
Enum-like column with no CHECK
b_mode is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE note_diff_files ADD CONSTRAINT note_diff_files_b_mode_check CHECK (b_mode IN (...));
F862notes typeundocumented-enum Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE notes ADD CONSTRAINT notes_type_check CHECK (type IN (...));
F922notes noteable_type, noteable_idpolymorphic-reference Polymorphic reference without referential integrity
noteable_id points at different tables depending on noteable_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
source_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE notification_settings ADD CONSTRAINT notification_settings_source_type_check CHECK (source_type IN (...));
Polymorphic reference without referential integrity
source_id points at different tables depending on source_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
owner_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE oauth_applications ADD CONSTRAINT oauth_applications_owner_type_check CHECK (owner_type IN (...));
Polymorphic reference without referential integrity
owner_id points at different tables depending on owner_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE organization_detail_uploads ADD CONSTRAINT organization_detail_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan p_ci_build_needs to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_build_needs maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_build_needs_partition_id_build_id ON p_ci_build_needs(partition_id, build_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_job_artifacts must scan p_ci_build_trace_metadata to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_build_trace_metadata maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_job_artifacts rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, trace_artifact_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_build_trace_metadata_partition_id_trace_artifact_id ON p_ci_build_trace_metadata(partition_id, trace_artifact_id) WHERE partition_id IS NOT NULL AND trace_artifact_id IS NOT NULL;
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_stages must scan p_ci_builds to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_builds maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_stages rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, stage_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_builds_partition_id_stage_id ON p_ci_builds(partition_id, stage_id) WHERE partition_id IS NOT NULL AND stage_id IS NOT NULL;
F004p_ci_builds upstream_pipeline_partition_id, upstream_pipeline_idfk-index Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_builds to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_builds maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. upstream_pipeline_partition_id, upstream_pipeline_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_builds_upstream_pipeline_partition_id_upstream_pipeline_id ON p_ci_builds(upstream_pipeline_partition_id, upstream_pipeline_id) WHERE upstream_pipeline_partition_id IS NOT NULL AND upstream_pipeline_id IS NOT NULL;
F005p_ci_builds auto_canceled_by_partition_id, auto_canceled_by_idfk-index Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_builds to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_builds maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. auto_canceled_by_partition_id, auto_canceled_by_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_builds_auto_canceled_by_partition_id_auto_canceled_by_id ON p_ci_builds(auto_canceled_by_partition_id, auto_canceled_by_id) WHERE auto_canceled_by_partition_id IS NOT NULL AND auto_canceled_by_id IS NOT NULL;
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_builds to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_builds maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, commit_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_builds_partition_id_commit_id ON p_ci_builds(partition_id, commit_id) WHERE partition_id IS NOT NULL AND commit_id IS NOT NULL;
Enum-like column with no CHECK
status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE p_ci_builds ADD CONSTRAINT p_ci_builds_status_check CHECK (status IN (...));
Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE p_ci_builds ADD CONSTRAINT p_ci_builds_type_check CHECK (type IN (...));
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan p_ci_builds_partition_overrides to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_builds_partition_overrides maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_builds_partition_overrides_partition_id_build_id ON p_ci_builds_partition_overrides(partition_id, build_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan p_ci_job_artifacts to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_job_artifacts maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_job_artifacts_partition_id_job_id ON p_ci_job_artifacts(partition_id, job_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_job_definitions must scan p_ci_job_definition_instances to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_job_definition_instances maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_job_definitions rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_job_definition_instances_partition_id_job_definition_id ON p_ci_job_definition_instances(partition_id, job_definition_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan p_ci_job_inputs to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_job_inputs maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_job_inputs_partition_id_job_id ON p_ci_job_inputs(partition_id, job_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_builds must scan p_ci_job_messages to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_job_messages maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_builds rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_job_messages_partition_id_job_id ON p_ci_job_messages(partition_id, job_id);
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_pipeline_variables to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_pipeline_variables maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add an index on the FK column(s).
CREATE INDEX CONCURRENTLY idx_p_ci_pipeline_variables_partition_id_pipeline_id ON p_ci_pipeline_variables(partition_id, pipeline_id);
F012p_ci_pipelines auto_canceled_by_partition_id, auto_canceled_by_idfk-index Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_pipelines to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_pipelines maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. auto_canceled_by_partition_id, auto_canceled_by_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_pipelines_auto_canceled_by_partition_id_auto_canceled_by_id ON p_ci_pipelines(auto_canceled_by_partition_id, auto_canceled_by_id) WHERE auto_canceled_by_partition_id IS NOT NULL AND auto_canceled_by_id IS NOT NULL;
Enum-like column with no CHECK
status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE p_ci_pipelines ADD CONSTRAINT p_ci_pipelines_status_check CHECK (status IN (...));
Foreign key without index
PostgreSQL does not index FK columns automatically. Every DELETE/UPDATE on p_ci_pipelines must scan p_ci_stages to check the constraint, and every join from the parent side is a sequential scan. The scan cost grows with the child table forever, so this gets worse on its own.
An index is not free. Every write to p_ci_stages maintains it — insert, update and delete alike — and it takes disk. Weigh that against how often p_ci_pipelines rows are actually deleted or re-keyed — if the answer is never, the scan never happens and the index only costs.
Fix Add a partial index, scoped to the rows that have a value. partition_id, pipeline_id is nullable, so the NULL rows are not indexed at all and the write cost is a fraction of a full index, while the constraint check still uses it.
CREATE INDEX CONCURRENTLY idx_p_ci_stages_partition_id_pipeline_id ON p_ci_stages(partition_id, pipeline_id) WHERE partition_id IS NOT NULL AND pipeline_id IS NOT NULL;
Polymorphic reference without referential integrity
noteable_id points at different tables depending on noteable_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE pool_repositories ADD CONSTRAINT pool_repositories_state_check CHECK (state IN (...));
Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE project_import_export_relation_export_upload_uploads ADD CONSTRAINT project_import_export_relation_export_upload_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE project_mirror_data ADD CONSTRAINT project_mirror_data_status_check CHECK (status IN (...));
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE project_topic_uploads ADD CONSTRAINT project_topic_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE project_uploads ADD CONSTRAINT project_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F816projects import_typeundocumented-enum Enum-like column with no CHECK
import_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE projects ADD CONSTRAINT projects_import_type_check CHECK (import_type IN (...));
Enum-like column with no CHECK
source_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE redirect_routes ADD CONSTRAINT redirect_routes_source_type_check CHECK (source_type IN (...));
Polymorphic reference without referential integrity
source_id points at different tables depending on source_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
update_status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE remote_mirrors ADD CONSTRAINT remote_mirrors_update_status_check CHECK (update_status IN (...));
F845routes source_typeundocumented-enum Enum-like column with no CHECK
source_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE routes ADD CONSTRAINT routes_source_type_check CHECK (source_type IN (...));
F915routes source_type, source_idpolymorphic-reference Polymorphic reference without referential integrity
source_id points at different tables depending on source_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE snippet_uploads ADD CONSTRAINT snippet_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE snippets ADD CONSTRAINT snippets_type_check CHECK (type IN (...));
Enum-like column with no CHECK
noteable_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE spam_logs ADD CONSTRAINT spam_logs_noteable_type_check CHECK (noteable_type IN (...));
Polymorphic reference without referential integrity
item_id points at different tables depending on item_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
subscribable_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE subscriptions ADD CONSTRAINT subscriptions_subscribable_type_check CHECK (subscribable_type IN (...));
F932subscriptions subscribable_type, subscribable_idpolymorphic-reference Polymorphic reference without referential integrity
subscribable_id points at different tables depending on subscribable_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Soft delete collides with non-partial UNIQUE
terraform_states soft-deletes via deleted_at, but (project_id, name) is unique across live AND deleted rows. A user who deletes their account can never sign up again with the same value, and ON CONFLICT upserts will resurrect ghosts.
Fix Replace with a partial unique index scoped to live rows.
DROP CONSTRAINT/INDEX ...; CREATE UNIQUE INDEX terraform_states_project_id_name_live ON terraform_states(project_id, name) WHERE deleted_at IS NULL;
Soft delete collides with non-partial UNIQUE
terraform_states soft-deletes via deleted_at, but (uuid) is unique across live AND deleted rows. A user who deletes their account can never sign up again with the same value, and ON CONFLICT upserts will resurrect ghosts.
Fix Replace with a partial unique index scoped to live rows.
DROP CONSTRAINT/INDEX ...; CREATE UNIQUE INDEX terraform_states_uuid_live ON terraform_states(uuid) WHERE deleted_at IS NULL;
F877todos target_typeundocumented-enum Enum-like column with no CHECK
target_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE todos ADD CONSTRAINT todos_target_type_check CHECK (target_type IN (...));
F878todos stateundocumented-enum Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE todos ADD CONSTRAINT todos_state_check CHECK (state IN (...));
F933todos target_type, target_idpolymorphic-reference Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F825uploads model_typeundocumented-enum Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE uploads ADD CONSTRAINT uploads_model_type_check CHECK (model_type IN (...));
F898uploads model_type, model_idpolymorphic-reference Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
subject_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE user_agent_details ADD CONSTRAINT user_agent_details_subject_type_check CHECK (subject_type IN (...));
Polymorphic reference without referential integrity
subject_id points at different tables depending on subject_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Polymorphic reference without referential integrity
target_id points at different tables depending on target_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE user_permission_export_upload_uploads ADD CONSTRAINT user_permission_export_upload_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE user_uploads ADD CONSTRAINT user_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
F817users stateundocumented-enum Enum-like column with no CHECK
state is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE users ADD CONSTRAINT users_state_check CHECK (state IN (...));
Foreign-key cycle
vulnerabilities → vulnerability_occurrences → vulnerabilities. Rows must be inserted with a deferred constraint or a NULL-then-update dance; backups/restores and truncation have no valid order; ON DELETE CASCADE can loop.
Fix Break the cycle (move one FK to a link table) or mark one FK DEFERRABLE INITIALLY DEFERRED.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE vulnerability_archive_export_uploads ADD CONSTRAINT vulnerability_archive_export_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE vulnerability_export_part_uploads ADD CONSTRAINT vulnerability_export_part_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE vulnerability_export_uploads ADD CONSTRAINT vulnerability_export_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
external_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE vulnerability_identifiers ADD CONSTRAINT vulnerability_identifiers_external_type_check CHECK (external_type IN (...));
Polymorphic reference without referential integrity
external_id points at different tables depending on external_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
model_type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE vulnerability_remediation_uploads ADD CONSTRAINT vulnerability_remediation_uploads_model_type_check CHECK (model_type IN (...));
Polymorphic reference without referential integrity
model_id points at different tables depending on model_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Enum-like column with no CHECK
response_status is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE web_hook_logs_daily ADD CONSTRAINT web_hook_logs_daily_response_status_check CHECK (response_status IN (...));
Enum-like column with no CHECK
type is a short string that clearly takes a fixed set of values, but the database accepts anything. Typos become new states, and nobody can list the legal values without reading application code.
Fix Add a CHECK constraint (cheap, easy to evolve) or a lookup table if values need metadata. Avoid native ENUM types unless the set is truly frozen.
ALTER TABLE web_hooks ADD CONSTRAINT web_hooks_type_check CHECK (type IN (...));
Polymorphic reference without referential integrity
item_id points at different tables depending on item_type. No FK can express that, so orphans accumulate silently and every join needs a CASE. Acceptable for append-only audit data; painful anywhere the target must still exist.
Fix Either one nullable FK per target with a CHECK that exactly one is set, or a supertype table that the targets reference.
Notes (1668)
Nullable foreign key
abuse_events.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_events.abuse_report_id may be NULL, so the relationship to abuse_reports is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F946abuse_events organization_id, user_id, abuse_report_idexclusive-arc Either/or foreign keys without a CHECK
abuse_events has several nullable FKs (organization_id, user_id, abuse_report_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE abuse_events ADD CONSTRAINT abuse_events_one_target CHECK ((organization_id IS NOT NULL)::int + (user_id IS NOT NULL)::int + (abuse_report_id IS NOT NULL)::int = 1);
Nullable foreign key
abuse_report_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_report_events.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
abuse_report_events has several nullable FKs (user_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE abuse_report_events ADD CONSTRAINT abuse_report_events_one_target CHECK ((user_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE abuse_report_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
abuse_report_user_mentions.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_reports.assignee_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_reports.reporter_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_reports.resolved_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
abuse_reports.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE abuse_reports ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE abuse_reports ALTER COLUMN updated_at TYPE timestamptz;
F949abuse_reports assignee_id, reporter_id, resolved_by_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
abuse_reports has several nullable FKs (assignee_id, reporter_id, resolved_by_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE abuse_reports ADD CONSTRAINT abuse_reports_one_target CHECK ((assignee_id IS NOT NULL)::int + (reporter_id IS NOT NULL)::int + (resolved_by_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE achievement_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
activation_metrics.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
admin_roles.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
agent_activity_events.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
agent_activity_events.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
agent_activity_events.agent_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
agent_activity_events.agent_token_id may be NULL, so the relationship to cluster_agent_tokens is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
agent_activity_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F950agent_activity_events project_id, merge_request_id, agent_project_id, agent_token_id, user_idexclusive-arc Either/or foreign keys without a CHECK
agent_activity_events has several nullable FKs (project_id, merge_request_id, agent_project_id, agent_token_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE agent_activity_events ADD CONSTRAINT agent_activity_events_one_target CHECK ((project_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int + (agent_project_id IS NOT NULL)::int + (agent_token_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
ai_active_context_tasks.depends_on_id may be NULL, so the relationship to ai_active_context_tasks is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
ai_audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ai_catalog_item_consumers.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_item_consumers.parent_item_consumer_id may be NULL, so the relationship to ai_catalog_item_consumers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_item_consumers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_item_consumers.service_account_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_item_consumers.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F951ai_catalog_item_consumers group_id, parent_item_consumer_id, project_id, service_account_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
ai_catalog_item_consumers has several nullable FKs (group_id, parent_item_consumer_id, project_id, service_account_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ai_catalog_item_consumers ADD CONSTRAINT ai_catalog_item_consumers_one_target CHECK ((group_id IS NOT NULL)::int + (parent_item_consumer_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (service_account_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Nullable foreign key
ai_catalog_item_versions.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_items.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_items.latest_released_version_id may be NULL, so the relationship to ai_catalog_item_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_items.latest_version_id may be NULL, so the relationship to ai_catalog_item_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F952ai_catalog_items project_id, latest_released_version_id, latest_version_idexclusive-arc Either/or foreign keys without a CHECK
ai_catalog_items has several nullable FKs (project_id, latest_released_version_id, latest_version_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ai_catalog_items ADD CONSTRAINT ai_catalog_items_one_target CHECK ((project_id IS NOT NULL)::int + (latest_released_version_id IS NOT NULL)::int + (latest_version_id IS NOT NULL)::int = 1);
Nullable foreign key
ai_catalog_mcp_server_blocks.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_catalog_mcp_servers.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_feature_settings.ai_self_hosted_model_id may be NULL, so the relationship to ai_self_hosted_models is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_flow_triggers.ai_catalog_item_consumer_id may be NULL, so the relationship to ai_catalog_item_consumers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
ai_instance_accessible_entity_rules references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ai_namespace_feature_access_rules.through_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F086ai_settings amazon_q_oauth_application_idfk-nullable Nullable foreign key
ai_settings.amazon_q_oauth_application_id may be NULL, so the relationship to oauth_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_settings.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F088ai_settings duo_workflow_oauth_application_idfk-nullable Nullable foreign key
ai_settings.duo_workflow_oauth_application_id may be NULL, so the relationship to oauth_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F089ai_settings duo_workflow_service_account_user_idfk-nullable Nullable foreign key
ai_settings.duo_workflow_service_account_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F090ai_settings amazon_q_service_account_user_idfk-nullable Nullable foreign key
ai_settings.amazon_q_service_account_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F953ai_settings amazon_q_oauth_application_id, organization_id, duo_workflow_oauth_application_id, duo_workflow_service_account_user_id, amazon_q_service_account_user_idexclusive-arc Either/or foreign keys without a CHECK
ai_settings has several nullable FKs (amazon_q_oauth_application_id, organization_id, duo_workflow_oauth_application_id, duo_workflow_service_account_user_id, amazon_q_service_account_user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ai_settings ADD CONSTRAINT ai_settings_one_target CHECK ((amazon_q_oauth_application_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (duo_workflow_oauth_application_id IS NOT NULL)::int + (duo_workflow_service_account_user_id IS NOT NULL)::int + (amazon_q_service_account_user_id IS NOT NULL)::int = 1);
Isolated table
ai_testing_terms_acceptances references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ai_tool_rules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ai_usage_events.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ai_vectorizable_file_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
alert_management_alert_assignees.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE alert_management_alert_metric_image_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
alert_management_alert_metric_images.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
alert_management_alert_user_mentions.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
alert_management_alert_user_mentions.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
alert_management_alert_user_mentions has several nullable FKs (project_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE alert_management_alert_user_mentions ADD CONSTRAINT alert_management_alert_user_mentions_one_target CHECK ((project_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
Nullable foreign key
alert_management_alerts.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
alert_management_alerts.environment_id may be NULL, so the relationship to environments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
alert_management_alerts has several nullable FKs (issue_id, environment_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE alert_management_alerts ADD CONSTRAINT alert_management_alerts_one_target CHECK ((issue_id IS NOT NULL)::int + (environment_id IS NOT NULL)::int = 1);
Nullable foreign key
analytics_cycle_analytics_group_stages.stage_event_hash_id may be NULL, so the relationship to analytics_cycle_analytics_stage_event_hashes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
analytics_cycle_analytics_group_stages.start_event_label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
analytics_cycle_analytics_group_stages.end_event_label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
analytics_cycle_analytics_group_stages has several nullable FKs (stage_event_hash_id, start_event_label_id, end_event_label_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE analytics_cycle_analytics_group_stages ADD CONSTRAINT analytics_cycle_analytics_group_stages_one_target CHECK ((stage_event_hash_id IS NOT NULL)::int + (start_event_label_id IS NOT NULL)::int + (end_event_label_id IS NOT NULL)::int = 1);
Isolated table
analytics_cycle_analytics_issue_stage_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_16 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_17 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_18 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_19 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_20 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_21 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_22 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_23 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_24 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_25 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_26 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_27 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_28 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_29 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_30 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_issue_stage_events_31 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_16 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_17 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_18 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_19 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_20 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_21 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_22 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_23 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_24 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_25 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_26 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_27 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_28 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_29 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_30 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analytics_cycle_analytics_merge_request_stage_events_31 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
analytics_dashboards_pointers.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
analytics_dashboards_pointers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
analytics_devops_adoption_segments.display_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
analytics_devops_adoption_segments.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
analytics_devops_adoption_segments has several nullable FKs (display_namespace_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE analytics_devops_adoption_segments ADD CONSTRAINT analytics_devops_adoption_segments_one_target CHECK ((display_namespace_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
analytics_devops_adoption_snapshots.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
analytics_usage_trends_measurements references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analyzer_namespace_statuses references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
analyzer_project_statuses references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE appearance_uploads ALTER COLUMN created_at TYPE timestamptz;
Isolated table
appearances references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
application_settings.duo_template_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
application_settings.o11y_oauth_application_id may be NULL, so the relationship to oauth_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
application_settings.workspaces_oauth_application_id may be NULL, so the relationship to oauth_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
application_settings.web_ide_oauth_application_id may be NULL, so the relationship to oauth_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE application_settings ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE application_settings ALTER COLUMN updated_at TYPE timestamptz;
Wide table (584 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F958application_settings duo_template_project_id, o11y_oauth_application_id, workspaces_oauth_application_id, web_ide_oauth_application_idexclusive-arc Either/or foreign keys without a CHECK
application_settings has several nullable FKs (duo_template_project_id, o11y_oauth_application_id, workspaces_oauth_application_id, web_ide_oauth_application_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE application_settings ADD CONSTRAINT application_settings_one_target CHECK ((duo_template_project_id IS NOT NULL)::int + (o11y_oauth_application_id IS NOT NULL)::int + (workspaces_oauth_application_id IS NOT NULL)::int + (web_ide_oauth_application_id IS NOT NULL)::int = 1);
Nullable foreign key
approval_group_rules.scan_result_policy_id may be NULL, so the relationship to scan_result_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_group_rules.approval_policy_rule_id may be NULL, so the relationship to approval_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_group_rules.security_orchestration_policy_configuration_id may be NULL, so the relationship to security_orchestration_policy_configurations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F959approval_group_rules scan_result_policy_id, approval_policy_rule_id, security_orchestration_policy_configuration_idexclusive-arc Either/or foreign keys without a CHECK
approval_group_rules has several nullable FKs (scan_result_policy_id, approval_policy_rule_id, security_orchestration_policy_configuration_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE approval_group_rules ADD CONSTRAINT approval_group_rules_one_target CHECK ((scan_result_policy_id IS NOT NULL)::int + (approval_policy_rule_id IS NOT NULL)::int + (security_orchestration_policy_configuration_id IS NOT NULL)::int = 1);
Nullable foreign key
approval_group_rules_protected_branches.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_group_rules_users.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_merge_request_rule_sources.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_merge_request_rules.security_orchestration_policy_configuration_id may be NULL, so the relationship to security_orchestration_policy_configurations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_merge_request_rules.scan_result_policy_id may be NULL, so the relationship to scan_result_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_merge_request_rules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
approval_merge_request_rules has several nullable FKs (security_orchestration_policy_configuration_id, scan_result_policy_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE approval_merge_request_rules ADD CONSTRAINT approval_merge_request_rules_one_target CHECK ((security_orchestration_policy_configuration_id IS NOT NULL)::int + (scan_result_policy_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
approval_merge_request_rules_approved_approvers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_merge_request_rules_users.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_policy_merge_request_bypass_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_project_rules.approval_policy_rule_id may be NULL, so the relationship to approval_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_project_rules.scan_result_policy_id may be NULL, so the relationship to scan_result_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_project_rules.security_orchestration_policy_configuration_id may be NULL, so the relationship to security_orchestration_policy_configurations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F961approval_project_rules approval_policy_rule_id, scan_result_policy_id, security_orchestration_policy_configuration_idexclusive-arc Either/or foreign keys without a CHECK
approval_project_rules has several nullable FKs (approval_policy_rule_id, scan_result_policy_id, security_orchestration_policy_configuration_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE approval_project_rules ADD CONSTRAINT approval_project_rules_one_target CHECK ((approval_policy_rule_id IS NOT NULL)::int + (scan_result_policy_id IS NOT NULL)::int + (security_orchestration_policy_configuration_id IS NOT NULL)::int = 1);
Nullable foreign key
approval_project_rules_protected_branches.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
approval_project_rules_users.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE approvals ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE approvals ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
approvals.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ar_internal_metadata ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ar_internal_metadata ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
ar_internal_metadata references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Wide table (30 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
ascp_scans.base_scan_id may be NULL, so the relationship to ascp_scans is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE audit_events ALTER COLUMN created_at TYPE timestamptz;
Isolated table
audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
audit_events_amazon_s3_configurations.stream_destination_id may be NULL, so the relationship to audit_events_group_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_external_audit_event_destinations.stream_destination_id may be NULL, so the relationship to audit_events_group_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_google_cloud_logging_configurations.stream_destination_id may be NULL, so the relationship to audit_events_group_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_instance_amazon_s3_configurations.stream_destination_id may be NULL, so the relationship to audit_events_instance_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_instance_external_audit_event_destinations.stream_destination_id may be NULL, so the relationship to audit_events_instance_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_instance_google_cloud_logging_configurations.stream_destination_id may be NULL, so the relationship to audit_events_instance_external_streaming_destinations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_streaming_event_type_filters.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
audit_events_streaming_headers.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
authentication_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE award_emoji ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE award_emoji ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
award_emoji.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
award_emoji.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
background_operation_jobs references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
background_operation_jobs_cell_local references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
background_operation_workers references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
background_operation_workers_cell_local references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_evidences references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_flags references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_identifiers references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_remediations references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_finding_signatures references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_findings references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerabilities references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_external_issue_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_issue_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_merge_request_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_reads references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_severity_overrides references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_state_transitions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
backup_vulnerability_user_mentions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F140badges project_idfk-nullable Nullable foreign key
badges.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F141badges group_idfk-nullable Nullable foreign key
badges.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_assignees.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_assignees.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_group_recent_visits.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_group_recent_visits.board_id may be NULL, so the relationship to boards is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_group_recent_visits.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
board_group_recent_visits has several nullable FKs (user_id, board_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE board_group_recent_visits ADD CONSTRAINT board_group_recent_visits_one_target CHECK ((user_id IS NOT NULL)::int + (board_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Nullable foreign key
board_labels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_labels.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_project_recent_visits.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_project_recent_visits.board_id may be NULL, so the relationship to boards is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_project_recent_visits.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
board_project_recent_visits has several nullable FKs (project_id, board_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE board_project_recent_visits ADD CONSTRAINT board_project_recent_visits_one_target CHECK ((project_id IS NOT NULL)::int + (board_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
board_user_preferences.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
board_user_preferences.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1138boards created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE boards ALTER COLUMN created_at TYPE timestamptz;
F1139boards updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE boards ALTER COLUMN updated_at TYPE timestamptz;
F154boards iteration_cadence_idfk-nullable Nullable foreign key
boards.iteration_cadence_id may be NULL, so the relationship to iterations_cadences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F155boards project_idfk-nullable Nullable foreign key
boards.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F156boards group_idfk-nullable Nullable foreign key
boards.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F964boards iteration_cadence_id, project_id, group_idexclusive-arc Either/or foreign keys without a CHECK
boards has several nullable FKs (iteration_cadence_id, project_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE boards ADD CONSTRAINT boards_one_target CHECK ((iteration_cadence_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Nullable foreign key
boards_epic_board_labels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
boards_epic_board_positions.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
boards_epic_list_user_preferences.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
boards_epic_lists.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
boards_epic_lists.label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
boards_epic_lists has several nullable FKs (group_id, label_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE boards_epic_lists ADD CONSTRAINT boards_epic_lists_one_target CHECK ((group_id IS NOT NULL)::int + (label_id IS NOT NULL)::int = 1);
Nullable foreign key
boards_epic_user_preferences.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
starts_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE broadcast_messages ALTER COLUMN starts_at TYPE timestamptz;
TIMESTAMP without time zone
ends_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE broadcast_messages ALTER COLUMN ends_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE broadcast_messages ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE broadcast_messages ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
bulk_import_batch_trackers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_batch_trackers.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_batch_trackers.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_configurations.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_entities.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_entities.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_entities.parent_id may be NULL, so the relationship to bulk_import_entities is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_entities.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
bulk_import_entities has several nullable FKs (organization_id, namespace_id, parent_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE bulk_import_entities ADD CONSTRAINT bulk_import_entities_one_target CHECK ((organization_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (parent_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
bulk_import_export_batches.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_export_batches.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE bulk_import_export_upload_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
bulk_import_export_uploads.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_export_uploads.batch_id may be NULL, so the relationship to bulk_import_export_batches is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_export_uploads.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
bulk_import_export_uploads has several nullable FKs (group_id, batch_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE bulk_import_export_uploads ADD CONSTRAINT bulk_import_export_uploads_one_target CHECK ((group_id IS NOT NULL)::int + (batch_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
bulk_import_exports.offline_export_id may be NULL, so the relationship to import_offline_exports is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_exports.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_exports.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_exports.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
bulk_import_exports has several nullable FKs (offline_export_id, project_id, group_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE bulk_import_exports ADD CONSTRAINT bulk_import_exports_one_target CHECK ((offline_export_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
bulk_import_failures.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_failures.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_failures.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_trackers.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_trackers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
bulk_import_trackers.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
catalog_resource_versions.published_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_applications.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_artifact_sources.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_artifact_sources.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cd_artifact_sources has several nullable FKs (group_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_artifact_sources ADD CONSTRAINT cd_artifact_sources_one_target CHECK ((group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_deployments.service_id may be NULL, so the relationship to cd_services is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_deployments.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_deployments.rollout_environment_id may be NULL, so the relationship to cd_rollout_environments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_deployments.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F970cd_deployments service_id, group_id, rollout_environment_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
cd_deployments has several nullable FKs (service_id, group_id, rollout_environment_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_deployments ADD CONSTRAINT cd_deployments_one_target CHECK ((service_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (rollout_environment_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_environments.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_rollout_environments.previous_version_set_id may be NULL, so the relationship to cd_version_sets is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_rollout_steps.rollout_environment_id may be NULL, so the relationship to cd_rollout_environments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F197cd_rollouts application_flow_definition_idfk-nullable Nullable foreign key
cd_rollouts.application_flow_definition_id may be NULL, so the relationship to cd_application_flow_definitions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_rollouts.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_rollouts.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_rollouts.application_id may be NULL, so the relationship to cd_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F971cd_rollouts application_flow_definition_id, organization_id, group_id, application_idexclusive-arc Either/or foreign keys without a CHECK
cd_rollouts has several nullable FKs (application_flow_definition_id, organization_id, group_id, application_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_rollouts ADD CONSTRAINT cd_rollouts_one_target CHECK ((application_flow_definition_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (application_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_services.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_services.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cd_services has several nullable FKs (group_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_services ADD CONSTRAINT cd_services_one_target CHECK ((group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_version_set_entries.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_version_set_entries.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_version_set_entries.artifact_source_id may be NULL, so the relationship to cd_artifact_sources is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cd_version_set_entries has several nullable FKs (group_id, organization_id, artifact_source_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_version_set_entries ADD CONSTRAINT cd_version_set_entries_one_target CHECK ((group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (artifact_source_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_version_sets.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_version_sets.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_version_sets.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cd_version_sets has several nullable FKs (created_by_id, group_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_version_sets ADD CONSTRAINT cd_version_sets_one_target CHECK ((created_by_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Nullable foreign key
cd_versions.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cd_versions.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cd_versions has several nullable FKs (organization_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cd_versions ADD CONSTRAINT cd_versions_one_target CHECK ((organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Isolated table
cells_outstanding_leases references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
last_used_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE chat_names ALTER COLUMN last_used_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE chat_names ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE chat_names ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
chat_names references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE chat_teams ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE chat_teams ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
ci_build_runtime_environments references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_deleted_objects references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_freeze_periods references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_gitlab_hosted_runner_monthly_usages references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_group_variables references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_instance_runner_monthly_usages references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_instance_variables references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_job_token_authorizations references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_job_token_group_scope_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_job_token_project_scope_links references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_minutes_additional_packs references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_namespace_mirrors references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_namespace_monthly_usages references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_partitions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
next_run_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_pipeline_schedules ALTER COLUMN next_run_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_pipeline_schedules ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_pipeline_schedules ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
ci_project_metrics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_project_mirrors references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_project_monthly_usages references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ci_resources.partition_id.build_id may be NULL, so the relationship to p_ci_builds is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
ci_runner_controller_runner_level_scopings_instance_type references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_runner_machines references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ci_runner_namespaces.runner_id may be NULL, so the relationship to group_type_ci_runners is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_runner_projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_runner_projects ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
ci_runner_taggings references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_runner_versions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_secure_file_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_secure_files references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
ci_sources_pipelines.source_partition_id.source_job_id may be NULL, so the relationship to p_ci_builds is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ci_sources_pipelines.source_partition_id.source_pipeline_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ci_sources_pipelines.partition_id.pipeline_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
ci_subscriptions_projects references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_triggers ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ci_triggers ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
ci_triggers references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
ci_variables references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
cloud_connector_access references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
cloud_connector_keys references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
cluster_agent_migrations.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_agent_tokens.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_agent_tokens.created_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
cluster_agent_tokens has several nullable FKs (project_id, created_by_user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE cluster_agent_tokens ADD CONSTRAINT cluster_agent_tokens_one_target CHECK ((project_id IS NOT NULL)::int + (created_by_user_id IS NOT NULL)::int = 1);
Nullable foreign key
cluster_agent_url_configurations.created_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_agents.created_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_platforms_kubernetes ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_platforms_kubernetes ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
cluster_platforms_kubernetes.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_platforms_kubernetes.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_platforms_kubernetes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_projects ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
cluster_providers_aws.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_providers_aws.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_providers_aws.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_providers_gcp ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE cluster_providers_gcp ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
cluster_providers_gcp.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_providers_gcp.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
cluster_providers_gcp.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE clusters ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE clusters ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
clusters.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F232clusters management_project_idfk-nullable Nullable foreign key
clusters.management_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F977clusters organization_id, group_id, management_project_id, project_id, user_idexclusive-arc Either/or foreign keys without a CHECK
clusters has several nullable FKs (organization_id, group_id, management_project_id, project_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE clusters ADD CONSTRAINT clusters_one_target CHECK ((organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (management_project_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
clusters_kubernetes_namespaces.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters_kubernetes_namespaces.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters_kubernetes_namespaces.sharding_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters_kubernetes_namespaces.cluster_project_id may be NULL, so the relationship to cluster_projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters_kubernetes_namespaces.environment_id may be NULL, so the relationship to environments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
clusters_kubernetes_namespaces.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
clusters_kubernetes_namespaces has several nullable FKs (organization_id, group_id, sharding_project_id, cluster_project_id, environment_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE clusters_kubernetes_namespaces ADD CONSTRAINT clusters_kubernetes_namespaces_one_target CHECK ((organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (sharding_project_id IS NOT NULL)::int + (cluster_project_id IS NOT NULL)::int + (environment_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
commit_user_mentions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
compliance_framework_security_policies.security_policy_id may be NULL, so the relationship to security_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
compliance_framework_security_policies.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
compliance_framework_security_policies.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
compliance_framework_security_policies has several nullable FKs (security_policy_id, namespace_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE compliance_framework_security_policies ADD CONSTRAINT compliance_framework_security_policies_one_target CHECK ((security_policy_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE container_repositories ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE container_repositories ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
container_repository_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
content_blocked_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE conversational_development_index_metrics ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE conversational_development_index_metrics ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
conversational_development_index_metrics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Wide table (34 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Isolated table
country_access_logs references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
coverage_fuzzing_corpuses.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
custom_dashboard_versions.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
custom_dashboards.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
custom_dashboards.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
custom_dashboards.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
custom_dashboards has several nullable FKs (created_by_id, namespace_id, updated_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE custom_dashboards ADD CONSTRAINT custom_dashboards_one_target CHECK ((created_by_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (updated_by_id IS NOT NULL)::int = 1);
Nullable foreign key
custom_fields.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
custom_fields.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
custom_fields has several nullable FKs (created_by_id, updated_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE custom_fields ADD CONSTRAINT custom_fields_one_target CHECK ((created_by_id IS NOT NULL)::int + (updated_by_id IS NOT NULL)::int = 1);
Nullable foreign key
customer_relations_contacts.organization_id may be NULL, so the relationship to customer_relations_organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
dast_sites.dast_site_validation_id may be NULL, so the relationship to dast_site_validations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
dependency_firewall_activity_stats.dependency_firewall_policy_rule_id may be NULL, so the relationship to dependency_firewall_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE dependency_list_export_part_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
dependency_list_export_upload_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
dependency_list_export_upload_states.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
dependency_list_export_upload_states.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE dependency_list_export_uploads ALTER COLUMN created_at TYPE timestamptz;
Isolated table
dependency_proxy_blob_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
dependency_proxy_manifest_states.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE deploy_keys_projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE deploy_keys_projects ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
deploy_tokens.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
deploy_tokens.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
deploy_tokens.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
deploy_tokens has several nullable FKs (project_id, creator_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE deploy_tokens ADD CONSTRAINT deploy_tokens_one_target CHECK ((project_id IS NOT NULL)::int + (creator_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Nullable foreign key
deployment_approvals.approval_rule_id may be NULL, so the relationship to protected_environment_approval_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
deployment_approvals.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
deployment_approvals has several nullable FKs (approval_rule_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE deployment_approvals ADD CONSTRAINT deployment_approvals_one_target CHECK ((approval_rule_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
deployment_clusters.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
deployment_merge_requests.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
deployment_merge_requests.environment_id may be NULL, so the relationship to environments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
deployment_merge_requests has several nullable FKs (project_id, environment_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE deployment_merge_requests ADD CONSTRAINT deployment_merge_requests_one_target CHECK ((project_id IS NOT NULL)::int + (environment_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE deployments ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE deployments ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
description_versions.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
description_versions.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
description_versions.epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE design_management_action_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
design_management_designs.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_designs.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
design_management_designs has several nullable FKs (namespace_id, issue_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE design_management_designs ADD CONSTRAINT design_management_designs_one_target CHECK ((namespace_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int = 1);
Nullable foreign key
design_management_designs_versions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_repositories.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_repository_states.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_versions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_versions.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
design_management_versions.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
design_management_versions has several nullable FKs (namespace_id, author_id, issue_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE design_management_versions ADD CONSTRAINT design_management_versions_one_target CHECK ((namespace_id IS NOT NULL)::int + (author_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int = 1);
Nullable foreign key
design_user_mentions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
detached_partitions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
diff_note_positions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
dora_daily_metrics.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
draft_notes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflow_session_artifacts.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflow_session_artifacts.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
duo_workflow_session_artifacts has several nullable FKs (project_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE duo_workflow_session_artifacts ADD CONSTRAINT duo_workflow_session_artifacts_one_target CHECK ((project_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
duo_workflows_checkpoint_writes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_checkpoint_writes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_events.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_events.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_merge_requests.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_merge_requests.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_notes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_notes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_pipelines.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_pipelines.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_work_items.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflow_work_items.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Wide table (34 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
duo_workflows_workflows.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.ai_catalog_item_version_id may be NULL, so the relationship to ai_catalog_item_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.ai_catalog_item_id may be NULL, so the relationship to ai_catalog_items is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.service_account_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.agent_identity_id may be NULL, so the relationship to ai_agent_identities is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
duo_workflows_workflows.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F988duo_workflows_workflows project_id, ai_catalog_item_version_id, namespace_id, issue_id, ai_catalog_item_id, service_account_id, agent_identity_id, merge_request_idexclusive-arc Either/or foreign keys without a CHECK
duo_workflows_workflows has several nullable FKs (project_id, ai_catalog_item_version_id, namespace_id, issue_id, ai_catalog_item_id, service_account_id, agent_identity_id, merge_request_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE duo_workflows_workflows ADD CONSTRAINT duo_workflows_workflows_one_target CHECK ((project_id IS NOT NULL)::int + (ai_catalog_item_version_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (ai_catalog_item_id IS NOT NULL)::int + (service_account_id IS NOT NULL)::int + (agent_identity_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int = 1);
Isolated table
elastic_index_settings references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1176emails created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE emails ALTER COLUMN created_at TYPE timestamptz;
F1177emails updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE emails ALTER COLUMN updated_at TYPE timestamptz;
F1178emails confirmed_attimestamp-tz TIMESTAMP without time zone
confirmed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE emails ALTER COLUMN confirmed_at TYPE timestamptz;
F1179emails confirmation_sent_attimestamp-tz TIMESTAMP without time zone
confirmation_sent_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE emails ALTER COLUMN confirmation_sent_at TYPE timestamptz;
Nullable foreign key
enabled_foundational_flows.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
enabled_foundational_flows.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE environments ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE environments ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
environments.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
environments.cluster_agent_id may be NULL, so the relationship to cluster_agents is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F989environments merge_request_id, cluster_agent_idexclusive-arc Either/or foreign keys without a CHECK
environments has several nullable FKs (merge_request_id, cluster_agent_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE environments ADD CONSTRAINT environments_one_target CHECK ((merge_request_id IS NOT NULL)::int + (cluster_agent_id IS NOT NULL)::int = 1);
Nullable foreign key
epic_issues.work_item_parent_link_id may be NULL, so the relationship to work_item_parent_links is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
epic_issues.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F990epic_issues work_item_parent_link_id, namespace_idexclusive-arc Either/or foreign keys without a CHECK
epic_issues has several nullable FKs (work_item_parent_link_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE epic_issues ADD CONSTRAINT epic_issues_one_target CHECK ((work_item_parent_link_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
epic_user_mentions.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
epic_user_mentions.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
epic_user_mentions has several nullable FKs (group_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE epic_user_mentions ADD CONSTRAINT epic_user_mentions_one_target CHECK ((group_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
F1182epics last_edited_attimestamp-tz TIMESTAMP without time zone
last_edited_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE epics ALTER COLUMN last_edited_at TYPE timestamptz;
F1183epics created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE epics ALTER COLUMN created_at TYPE timestamptz;
F1184epics updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE epics ALTER COLUMN updated_at TYPE timestamptz;
F1185epics closed_attimestamp-tz TIMESTAMP without time zone
closed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE epics ALTER COLUMN closed_at TYPE timestamptz;
Wide table (42 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F313epics due_date_sourcing_epic_idfk-nullable Nullable foreign key
epics.due_date_sourcing_epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F314epics start_date_sourcing_milestone_idfk-nullable Nullable foreign key
epics.start_date_sourcing_milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F315epics due_date_sourcing_milestone_idfk-nullable Nullable foreign key
epics.due_date_sourcing_milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F316epics work_item_parent_link_idfk-nullable Nullable foreign key
epics.work_item_parent_link_id may be NULL, so the relationship to work_item_parent_links is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F317epics start_date_sourcing_epic_idfk-nullable Nullable foreign key
epics.start_date_sourcing_epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F318epics closed_by_idfk-nullable Nullable foreign key
epics.closed_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F319epics assignee_idfk-nullable Nullable foreign key
epics.assignee_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F320epics issue_idfk-nullable Nullable foreign key
epics.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F321epics parent_idfk-nullable Nullable foreign key
epics.parent_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F992epics due_date_sourcing_epic_id, start_date_sourcing_milestone_id, due_date_sourcing_milestone_id, work_item_parent_link_id, start_date_sourcing_epic_id, closed_by_id, assignee_id, issue_id, parent_idexclusive-arc Either/or foreign keys without a CHECK
epics has several nullable FKs (due_date_sourcing_epic_id, start_date_sourcing_milestone_id, due_date_sourcing_milestone_id, work_item_parent_link_id, start_date_sourcing_epic_id, closed_by_id, assignee_id, issue_id, parent_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE epics ADD CONSTRAINT epics_one_target CHECK ((due_date_sourcing_epic_id IS NOT NULL)::int + (start_date_sourcing_milestone_id IS NOT NULL)::int + (due_date_sourcing_milestone_id IS NOT NULL)::int + (work_item_parent_link_id IS NOT NULL)::int + (start_date_sourcing_epic_id IS NOT NULL)::int + (closed_by_id IS NOT NULL)::int + (assignee_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (parent_id IS NOT NULL)::int = 1);
Nullable foreign key
error_tracking_error_events.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F323events personal_namespace_idfk-nullable Nullable foreign key
events.personal_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F324events project_idfk-nullable Nullable foreign key
events.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F325events group_idfk-nullable Nullable foreign key
events.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
evidences.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
external_status_checks_protected_branches.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE feature_gates ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE feature_gates ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
feature_gates references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE features ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE features ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
features references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
fork_network_members.forked_from_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
fork_networks.root_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
geo_ci_job_artifact_verification_summaries references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_event_log ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
geo_event_log.cache_invalidation_event_id may be NULL, so the relationship to geo_cache_invalidation_events is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
geo_event_log.geo_event_id may be NULL, so the relationship to geo_events is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F993geo_event_log cache_invalidation_event_id, geo_event_idexclusive-arc Either/or foreign keys without a CHECK
geo_event_log has several nullable FKs (cache_invalidation_event_id, geo_event_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE geo_event_log ADD CONSTRAINT geo_event_log_one_target CHECK ((cache_invalidation_event_id IS NOT NULL)::int + (geo_event_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_namespace_links ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_namespace_links ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
last_event_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_statuses ALTER COLUMN last_event_date TYPE timestamptz;
TIMESTAMP without time zone
cursor_last_event_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_statuses ALTER COLUMN cursor_last_event_date TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_statuses ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_statuses ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
last_successful_status_check_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE geo_node_statuses ALTER COLUMN last_successful_status_check_at TYPE timestamptz;
Isolated table
gitlab_subscription_histories references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
gitlab_subscriptions.hosted_plan_id may be NULL, so the relationship to plans is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
gitlab_subscriptions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
gitlab_subscriptions has several nullable FKs (hosted_plan_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE gitlab_subscriptions ADD CONSTRAINT gitlab_subscriptions_one_target CHECK ((hosted_plan_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
gpg_key_subkeys.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
gpg_keys.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
gpg_signatures.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
gpg_signatures.gpg_key_subkey_id may be NULL, so the relationship to gpg_key_subkeys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
gpg_signatures.gpg_key_id may be NULL, so the relationship to gpg_keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F995gpg_signatures project_id, gpg_key_subkey_id, gpg_key_idexclusive-arc Either/or foreign keys without a CHECK
gpg_signatures has several nullable FKs (project_id, gpg_key_subkey_id, gpg_key_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE gpg_signatures ADD CONSTRAINT gpg_signatures_one_target CHECK ((project_id IS NOT NULL)::int + (gpg_key_subkey_id IS NOT NULL)::int + (gpg_key_id IS NOT NULL)::int = 1);
Nullable foreign key
granular_scopes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
group_audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
group_crm_settings.source_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
group_group_links.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
group_import_states.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
group_secrets_manager_maintenance_tasks references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
group_secrets_managers.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
group_security_exclusions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
group_wiki_repository_states.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
groups_visits references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE historical_data ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE historical_data ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
historical_data references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE identities ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE identities ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
identities.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
identities.saml_provider_id may be NULL, so the relationship to saml_providers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F996identities user_id, saml_provider_idexclusive-arc Either/or foreign keys without a CHECK
identities has several nullable FKs (user_id, saml_provider_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE identities ADD CONSTRAINT identities_one_target CHECK ((user_id IS NOT NULL)::int + (saml_provider_id IS NOT NULL)::int = 1);
Nullable foreign key
import_export_upload_upload_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_export_upload_upload_states.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE import_export_upload_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
import_export_uploads.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_export_uploads.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_export_uploads.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
import_export_uploads has several nullable FKs (user_id, group_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE import_export_uploads ADD CONSTRAINT import_export_uploads_one_target CHECK ((user_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
import_failures.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_failures.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_failures.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_failures.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F998import_failures group_id, organization_id, user_id, project_idexclusive-arc Either/or foreign keys without a CHECK
import_failures has several nullable FKs (group_id, organization_id, user_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE import_failures ADD CONSTRAINT import_failures_one_target CHECK ((group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (user_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
import_offline_configurations.bulk_import_id may be NULL, so the relationship to bulk_imports is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_offline_configurations.offline_export_id may be NULL, so the relationship to import_offline_exports is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_placeholder_memberships.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_placeholder_memberships.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
import_placeholder_memberships has several nullable FKs (group_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE import_placeholder_memberships ADD CONSTRAINT import_placeholder_memberships_one_target CHECK ((group_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
import_placeholder_user_details.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1000import_source_users reassigned_by_user_id, reassign_to_user_id, placeholder_user_idexclusive-arc Either/or foreign keys without a CHECK
import_source_users has several nullable FKs (reassigned_by_user_id, reassign_to_user_id, placeholder_user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE import_source_users ADD CONSTRAINT import_source_users_one_target CHECK ((reassigned_by_user_id IS NOT NULL)::int + (reassign_to_user_id IS NOT NULL)::int + (placeholder_user_id IS NOT NULL)::int = 1);
Nullable foreign key
import_source_users.reassigned_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_source_users.reassign_to_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
import_source_users.placeholder_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
incident_management_escalation_rules has several nullable FKs (user_id, project_id, oncall_schedule_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE incident_management_escalation_rules ADD CONSTRAINT incident_management_escalation_rules_one_target CHECK ((user_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (oncall_schedule_id IS NOT NULL)::int = 1);
Nullable foreign key
incident_management_escalation_rules.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_escalation_rules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_escalation_rules.oncall_schedule_id may be NULL, so the relationship to incident_management_oncall_schedules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
incident_management_issuable_escalation_statuses has several nullable FKs (namespace_id, policy_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE incident_management_issuable_escalation_statuses ADD CONSTRAINT incident_management_issuable_escalation_statuses_one_target CHECK ((namespace_id IS NOT NULL)::int + (policy_id IS NOT NULL)::int = 1);
Nullable foreign key
incident_management_issuable_escalation_statuses.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_issuable_escalation_statuses.policy_id may be NULL, so the relationship to incident_management_escalation_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_oncall_participants.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_oncall_rotations.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_oncall_shifts.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_pending_alert_escalations.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_pending_issue_escalations.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_timeline_event_tag_links.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
incident_management_timeline_events has several nullable FKs (author_id, updated_by_user_id, promoted_from_note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE incident_management_timeline_events ADD CONSTRAINT incident_management_timeline_events_one_target CHECK ((author_id IS NOT NULL)::int + (updated_by_user_id IS NOT NULL)::int + (promoted_from_note_id IS NOT NULL)::int = 1);
Nullable foreign key
incident_management_timeline_events.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_timeline_events.updated_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
incident_management_timeline_events.promoted_from_note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
indexed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE index_statuses ALTER COLUMN indexed_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE index_statuses ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE index_statuses ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
instance_audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
instance_model_selection_feature_settings references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1004integrations project_id, organization_id, group_id, inherit_from_idexclusive-arc Either/or foreign keys without a CHECK
integrations has several nullable FKs (project_id, organization_id, group_id, inherit_from_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE integrations ADD CONSTRAINT integrations_one_target CHECK ((project_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (inherit_from_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE integrations ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE integrations ALTER COLUMN updated_at TYPE timestamptz;
Wide table (35 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
integrations.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
integrations.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
integrations.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
integrations.inherit_from_id may be NULL, so the relationship to integrations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
internal_ids.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
internal_ids.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issuable_metric_image_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
issuable_metric_images.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issuable_resource_links.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issuable_severities.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issuable_slas.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_assignees.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
issue_assignment_events has several nullable FKs (namespace_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE issue_assignment_events ADD CONSTRAINT issue_assignment_events_one_target CHECK ((namespace_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
issue_assignment_events.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_assignment_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_customer_relations_contacts.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_email_participants.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_emails.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_links ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_links ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
issue_links.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
first_mentioned_in_commit_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_metrics ALTER COLUMN first_mentioned_in_commit_at TYPE timestamptz;
F1214issue_metrics first_associated_with_milestone_attimestamp-tz TIMESTAMP without time zone
first_associated_with_milestone_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_metrics ALTER COLUMN first_associated_with_milestone_at TYPE timestamptz;
TIMESTAMP without time zone
first_added_to_board_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_metrics ALTER COLUMN first_added_to_board_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_metrics ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issue_metrics ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
issue_metrics.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_search_data.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
issue_search_data_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_16 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_17 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_18 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_19 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_20 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_21 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_22 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_23 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_24 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_25 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_26 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_27 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_28 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_29 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_30 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_31 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_32 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_33 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_34 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_35 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_36 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_37 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_38 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_39 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_40 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_41 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_42 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_43 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_44 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_45 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_46 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_47 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_48 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_49 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_50 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_51 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_52 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_53 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_54 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_55 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_56 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_57 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_58 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_59 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_60 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_61 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_62 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
issue_search_data_63 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1006issue_tracker_data integration_id, group_id, organization_id, project_idexclusive-arc Either/or foreign keys without a CHECK
issue_tracker_data has several nullable FKs (integration_id, group_id, organization_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE issue_tracker_data ADD CONSTRAINT issue_tracker_data_one_target CHECK ((integration_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Nullable foreign key
issue_tracker_data.integration_id may be NULL, so the relationship to integrations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_tracker_data.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_tracker_data.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_tracker_data.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
issue_user_mentions has several nullable FKs (namespace_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE issue_user_mentions ADD CONSTRAINT issue_user_mentions_one_target CHECK ((namespace_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
Nullable foreign key
issue_user_mentions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
issue_user_mentions.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1008issues author_id, sprint_id, project_id, milestone_id, duplicated_to_id, moved_to_id, closed_by_id, namespace_id, promoted_to_epic_id, updated_by_idexclusive-arc Either/or foreign keys without a CHECK
issues has several nullable FKs (author_id, sprint_id, project_id, milestone_id, duplicated_to_id, moved_to_id, closed_by_id, namespace_id, promoted_to_epic_id, updated_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE issues ADD CONSTRAINT issues_one_target CHECK ((author_id IS NOT NULL)::int + (sprint_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (milestone_id IS NOT NULL)::int + (duplicated_to_id IS NOT NULL)::int + (moved_to_id IS NOT NULL)::int + (closed_by_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (promoted_to_epic_id IS NOT NULL)::int + (updated_by_id IS NOT NULL)::int = 1);
F1218issues created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issues ALTER COLUMN created_at TYPE timestamptz;
F1219issues updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issues ALTER COLUMN updated_at TYPE timestamptz;
F1220issues last_edited_attimestamp-tz TIMESTAMP without time zone
last_edited_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE issues ALTER COLUMN last_edited_at TYPE timestamptz;
Wide table (38 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F401issues author_idfk-nullable Nullable foreign key
issues.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F402issues sprint_idfk-nullable Nullable foreign key
issues.sprint_id may be NULL, so the relationship to sprints is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F403issues project_idfk-nullable Nullable foreign key
issues.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F404issues milestone_idfk-nullable Nullable foreign key
issues.milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F405issues duplicated_to_idfk-nullable Nullable foreign key
issues.duplicated_to_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F406issues moved_to_idfk-nullable Nullable foreign key
issues.moved_to_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F407issues closed_by_idfk-nullable Nullable foreign key
issues.closed_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F408issues namespace_idfk-nullable Nullable foreign key
issues.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F409issues promoted_to_epic_idfk-nullable Nullable foreign key
issues.promoted_to_epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F410issues updated_by_idfk-nullable Nullable foreign key
issues.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
jira_connect_installations.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
jira_imports has several nullable FKs (label_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE jira_imports ADD CONSTRAINT jira_imports_one_target CHECK ((label_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
jira_imports.label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
jira_imports.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1010jira_tracker_data organization_id, group_id, integration_id, project_idexclusive-arc Either/or foreign keys without a CHECK
jira_tracker_data has several nullable FKs (organization_id, group_id, integration_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE jira_tracker_data ADD CONSTRAINT jira_tracker_data_one_target CHECK ((organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (integration_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
Wide table (32 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
jira_tracker_data.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
jira_tracker_data.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
jira_tracker_data.integration_id may be NULL, so the relationship to integrations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
jira_tracker_data.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
job_environments.deployment_id may be NULL, so the relationship to deployments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1221keys created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE keys ALTER COLUMN created_at TYPE timestamptz;
F1222keys updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE keys ALTER COLUMN updated_at TYPE timestamptz;
F1223keys last_used_attimestamp-tz TIMESTAMP without time zone
last_used_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE keys ALTER COLUMN last_used_at TYPE timestamptz;
F419keys organization_idfk-nullable Nullable foreign key
keys.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
label_links has several nullable FKs (namespace_id, label_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE label_links ADD CONSTRAINT label_links_one_target CHECK ((namespace_id IS NOT NULL)::int + (label_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE label_links ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE label_links ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
label_links.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
label_links.label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE label_priorities ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE label_priorities ALTER COLUMN updated_at TYPE timestamptz;
F1228labels created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE labels ALTER COLUMN created_at TYPE timestamptz;
F1229labels updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE labels ALTER COLUMN updated_at TYPE timestamptz;
F422labels project_idfk-nullable Nullable foreign key
labels.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F423labels organization_idfk-nullable Nullable foreign key
labels.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F424labels group_idfk-nullable Nullable foreign key
labels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ldap_admin_role_links.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ldap_group_links ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE ldap_group_links ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
ldap_group_links.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lfs_file_locks ALTER COLUMN created_at TYPE timestamptz;
Isolated table
lfs_object_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lfs_objects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lfs_objects ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
lfs_objects references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lfs_objects_projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lfs_objects_projects ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE licenses ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE licenses ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
licenses references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1012lists custom_status_id, iteration_id, project_id, label_id, user_id, group_id, milestone_idexclusive-arc Either/or foreign keys without a CHECK
lists has several nullable FKs (custom_status_id, iteration_id, project_id, label_id, user_id, group_id, milestone_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE lists ADD CONSTRAINT lists_one_target CHECK ((custom_status_id IS NOT NULL)::int + (iteration_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (label_id IS NOT NULL)::int + (user_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (milestone_id IS NOT NULL)::int = 1);
F1239lists created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lists ALTER COLUMN created_at TYPE timestamptz;
F1240lists updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE lists ALTER COLUMN updated_at TYPE timestamptz;
F427lists custom_status_idfk-nullable Nullable foreign key
lists.custom_status_id may be NULL, so the relationship to work_item_custom_statuses is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F428lists iteration_idfk-nullable Nullable foreign key
lists.iteration_id may be NULL, so the relationship to sprints is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F429lists project_idfk-nullable Nullable foreign key
lists.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F430lists label_idfk-nullable Nullable foreign key
lists.label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F431lists user_idfk-nullable Nullable foreign key
lists.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F432lists group_idfk-nullable Nullable foreign key
lists.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F433lists milestone_idfk-nullable Nullable foreign key
lists.milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
loose_foreign_keys_deleted_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
loose_foreign_keys_namespace_deleted_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
loose_foreign_keys_organization_deleted_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
loose_foreign_keys_project_deleted_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
loose_foreign_keys_user_deleted_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Either/or foreign keys without a CHECK
member_approvals has several nullable FKs (member_role_id, member_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE member_approvals ADD CONSTRAINT member_approvals_one_target CHECK ((member_role_id IS NOT NULL)::int + (member_id IS NOT NULL)::int = 1);
Nullable foreign key
member_approvals.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
member_approvals.member_id may be NULL, so the relationship to members is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
member_roles.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
member_roles.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1014members member_namespace_id, member_role_idexclusive-arc Either/or foreign keys without a CHECK
members has several nullable FKs (member_namespace_id, member_role_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE members ADD CONSTRAINT members_one_target CHECK ((member_namespace_id IS NOT NULL)::int + (member_role_id IS NOT NULL)::int = 1);
F1241members created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE members ALTER COLUMN created_at TYPE timestamptz;
F1242members updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE members ALTER COLUMN updated_at TYPE timestamptz;
F1243members invite_accepted_attimestamp-tz TIMESTAMP without time zone
invite_accepted_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE members ALTER COLUMN invite_accepted_at TYPE timestamptz;
F1244members requested_attimestamp-tz TIMESTAMP without time zone
requested_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE members ALTER COLUMN requested_at TYPE timestamptz;
F438members member_namespace_idfk-nullable Nullable foreign key
members.member_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F439members member_role_idfk-nullable Nullable foreign key
members.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_assignees.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
merge_request_assignment_events has several nullable FKs (project_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_request_assignment_events ADD CONSTRAINT merge_request_assignment_events_one_target CHECK ((project_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
merge_request_assignment_events.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_assignment_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_blocks.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_cleanup_schedules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
authored_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_commits_metadata ALTER COLUMN authored_date TYPE timestamptz;
TIMESTAMP without time zone
committed_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_commits_metadata ALTER COLUMN committed_date TYPE timestamptz;
Isolated table
merge_request_commits_metadata references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
merge_request_context_commit_diff_files.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
merge_request_context_commits has several nullable FKs (project_id, merge_request_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_request_context_commits ADD CONSTRAINT merge_request_context_commits_one_target CHECK ((project_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int = 1);
Nullable foreign key
merge_request_context_commits.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_context_commits.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
authored_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_diff_commits ALTER COLUMN authored_date TYPE timestamptz;
TIMESTAMP without time zone
committed_date stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_diff_commits ALTER COLUMN committed_date TYPE timestamptz;
Isolated table
merge_request_diff_commits references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
merge_request_diff_commits_b5377a7a34 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
merge_request_diff_details.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_diff_files.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
merge_request_diff_files_99208b8fac references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_diffs ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_diffs ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
merge_request_diffs.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
merge_request_metrics has several nullable FKs (target_project_id, merged_by_id, latest_closed_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_request_metrics ADD CONSTRAINT merge_request_metrics_one_target CHECK ((target_project_id IS NOT NULL)::int + (merged_by_id IS NOT NULL)::int + (latest_closed_by_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
latest_build_started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN latest_build_started_at TYPE timestamptz;
TIMESTAMP without time zone
latest_build_finished_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN latest_build_finished_at TYPE timestamptz;
TIMESTAMP without time zone
first_deployed_to_production_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN first_deployed_to_production_at TYPE timestamptz;
TIMESTAMP without time zone
merged_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN merged_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_request_metrics ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
merge_request_metrics.target_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_metrics.merged_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_metrics.latest_closed_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_predictions.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
merge_request_requested_changes references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
merge_request_reviewers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
merge_request_user_mentions has several nullable FKs (project_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_request_user_mentions ADD CONSTRAINT merge_request_user_mentions_one_target CHECK ((project_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
Nullable foreign key
merge_request_user_mentions.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_request_user_mentions.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1019merge_requests latest_merge_request_diff_id, assignee_id, updated_by_id, milestone_id, merge_user_id, author_id, source_project_idexclusive-arc Either/or foreign keys without a CHECK
merge_requests has several nullable FKs (latest_merge_request_diff_id, assignee_id, updated_by_id, milestone_id, merge_user_id, author_id, source_project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_requests ADD CONSTRAINT merge_requests_one_target CHECK ((latest_merge_request_diff_id IS NOT NULL)::int + (assignee_id IS NOT NULL)::int + (updated_by_id IS NOT NULL)::int + (milestone_id IS NOT NULL)::int + (merge_user_id IS NOT NULL)::int + (author_id IS NOT NULL)::int + (source_project_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_requests ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_requests ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
last_edited_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_requests ALTER COLUMN last_edited_at TYPE timestamptz;
Wide table (46 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
merge_requests.latest_merge_request_diff_id may be NULL, so the relationship to merge_request_diffs is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.assignee_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.merge_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests.source_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
merge_requests_approval_rules has several nullable FKs (group_id, project_id, source_rule_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE merge_requests_approval_rules ADD CONSTRAINT merge_requests_approval_rules_one_target CHECK ((group_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (source_rule_id IS NOT NULL)::int = 1);
Nullable foreign key
merge_requests_approval_rules.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_approval_rules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_approval_rules.source_rule_id may be NULL, so the relationship to merge_requests_approval_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_approval_rules_approver_users.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_approval_rules_approver_users.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_requests_closing_issues ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE merge_requests_closing_issues ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
merge_requests_closing_issues.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_compliance_violations.target_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
merge_requests_merge_data.merge_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
milestone_releases.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE milestones ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE milestones ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
milestones.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
milestones.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidate_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
ml_candidate_metrics has several nullable FKs (project_id, candidate_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ml_candidate_metrics ADD CONSTRAINT ml_candidate_metrics_one_target CHECK ((project_id IS NOT NULL)::int + (candidate_id IS NOT NULL)::int = 1);
Nullable foreign key
ml_candidate_metrics.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidate_metrics.candidate_id may be NULL, so the relationship to ml_candidates is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
ml_candidate_params has several nullable FKs (project_id, candidate_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ml_candidate_params ADD CONSTRAINT ml_candidate_params_one_target CHECK ((project_id IS NOT NULL)::int + (candidate_id IS NOT NULL)::int = 1);
Nullable foreign key
ml_candidate_params.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidate_params.candidate_id may be NULL, so the relationship to ml_candidates is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1023ml_candidates project_id, package_id, model_version_id, user_idexclusive-arc Either/or foreign keys without a CHECK
ml_candidates has several nullable FKs (project_id, package_id, model_version_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ml_candidates ADD CONSTRAINT ml_candidates_one_target CHECK ((project_id IS NOT NULL)::int + (package_id IS NOT NULL)::int + (model_version_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
ml_candidates.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidates.package_id may be NULL, so the relationship to packages_packages is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidates.model_version_id may be NULL, so the relationship to ml_model_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_candidates.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_experiment_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
ml_experiments has several nullable FKs (user_id, model_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ml_experiments ADD CONSTRAINT ml_experiments_one_target CHECK ((user_id IS NOT NULL)::int + (model_id IS NOT NULL)::int = 1);
Nullable foreign key
ml_experiments.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_experiments.model_id may be NULL, so the relationship to ml_models is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_model_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_model_versions.package_id may be NULL, so the relationship to packages_packages is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ml_models.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
namespace_cluster_agent_mappings.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
namespace_descendants references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_16 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_17 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_18 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_19 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_20 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_21 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_22 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_23 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_24 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_25 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_26 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_27 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_28 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_29 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_30 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
namespace_descendants_31 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Wide table (101 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
namespace_settings.default_compliance_framework_id may be NULL, so the relationship to compliance_management_frameworks is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
shared_runners_seconds_last_reset stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespace_statistics ALTER COLUMN shared_runners_seconds_last_reset TYPE timestamptz;
Either/or foreign keys without a CHECK
namespace_template_settings has several nullable FKs (custom_project_templates_group_id, file_template_project_id, duo_template_project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE namespace_template_settings ADD CONSTRAINT namespace_template_settings_one_target CHECK ((custom_project_templates_group_id IS NOT NULL)::int + (file_template_project_id IS NOT NULL)::int + (duo_template_project_id IS NOT NULL)::int = 1);
Nullable foreign key
namespace_template_settings.custom_project_templates_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
namespace_template_settings.file_template_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
namespace_template_settings.duo_template_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespace_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
namespaces.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
namespaces.parent_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespaces ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespaces ALTER COLUMN updated_at TYPE timestamptz;
F1078namespaces ldap_sync_last_update_attimestamp-tz TIMESTAMP without time zone
ldap_sync_last_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespaces ALTER COLUMN ldap_sync_last_update_at TYPE timestamptz;
F1079namespaces ldap_sync_last_successful_update_attimestamp-tz TIMESTAMP without time zone
ldap_sync_last_successful_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespaces ALTER COLUMN ldap_sync_last_successful_update_at TYPE timestamptz;
F1080namespaces ldap_sync_last_sync_attimestamp-tz TIMESTAMP without time zone
ldap_sync_last_sync_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE namespaces ALTER COLUMN ldap_sync_last_sync_at TYPE timestamptz;
Hub table: referenced by 353 tables
Any change to its key, its delete semantics, or its partitioning touches every dependent. Migrations on hub tables need the longest lock windows and the most careful rollout.
Fix Treat schema changes here as breaking changes with a written rollout plan.
Wide table (44 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F943namespaces organization_id, parent_idexclusive-arc Either/or foreign keys without a CHECK
namespaces has several nullable FKs (organization_id, parent_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE namespaces ADD CONSTRAINT namespaces_one_target CHECK ((organization_id IS NOT NULL)::int + (parent_id IS NOT NULL)::int = 1);
Nullable foreign key
note_diff_files.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
note_metadata.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1026notes review_id, namespace_id, project_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
notes has several nullable FKs (review_id, namespace_id, project_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE notes ADD CONSTRAINT notes_one_target CHECK ((review_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
F1264notes created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE notes ALTER COLUMN created_at TYPE timestamptz;
F1265notes updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE notes ALTER COLUMN updated_at TYPE timestamptz;
F1266notes resolved_attimestamp-tz TIMESTAMP without time zone
resolved_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE notes ALTER COLUMN resolved_at TYPE timestamptz;
Wide table (30 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F497notes review_idfk-nullable Nullable foreign key
notes.review_id may be NULL, so the relationship to reviews is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F498notes namespace_idfk-nullable Nullable foreign key
notes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F499notes project_idfk-nullable Nullable foreign key
notes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F500notes organization_idfk-nullable Nullable foreign key
notes.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE notification_settings ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE notification_settings ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
notification_settings references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Wide table (32 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_access_grants ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
revoked_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_access_grants ALTER COLUMN revoked_at TYPE timestamptz;
TIMESTAMP without time zone
revoked_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_access_tokens ALTER COLUMN revoked_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_access_tokens ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_applications ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE oauth_applications ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
oauth_applications.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
observability_metrics_issues_connections.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
operations_feature_flags_issues.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
operations_scopes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
operations_strategies.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
operations_strategies_user_lists.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
organization_cluster_agent_mappings.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE organization_detail_uploads ALTER COLUMN created_at TYPE timestamptz;
Isolated table
p_ai_active_context_code_repositories references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_batched_git_ref_updates_deletions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_catalog_resource_sync_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
p_ci_build_trace_metadata.partition_id.trace_artifact_id may be NULL, so the relationship to p_ci_job_artifacts is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
p_ci_builds.partition_id.stage_id may be NULL, so the relationship to p_ci_stages is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
p_ci_builds.resource_group_id may be NULL, so the relationship to ci_resource_groups is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F036p_ci_builds upstream_pipeline_partition_id, upstream_pipeline_idfk-nullable Nullable foreign key
p_ci_builds.upstream_pipeline_partition_id.upstream_pipeline_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F037p_ci_builds auto_canceled_by_partition_id, auto_canceled_by_idfk-nullable Nullable foreign key
p_ci_builds.auto_canceled_by_partition_id.auto_canceled_by_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
p_ci_builds.partition_id.commit_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
finished_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN finished_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN started_at TYPE timestamptz;
TIMESTAMP without time zone
erased_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN erased_at TYPE timestamptz;
TIMESTAMP without time zone
artifacts_expire_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN artifacts_expire_at TYPE timestamptz;
TIMESTAMP without time zone
queued_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_builds ALTER COLUMN queued_at TYPE timestamptz;
Wide table (47 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Isolated table
p_ci_builds_partition_overrides_0 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_builds_partition_overrides_1 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_builds_partition_overrides_2 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
build_finished_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_finished_build_ch_sync_events ALTER COLUMN build_finished_at TYPE timestamptz;
Isolated table
p_ci_finished_build_ch_sync_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
pipeline_finished_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_finished_pipeline_ch_sync_events ALTER COLUMN pipeline_finished_at TYPE timestamptz;
Isolated table
p_ci_finished_pipeline_ch_sync_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_job_runtime_environments references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_artifact_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_16 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_17 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_18 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_19 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_20 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_21 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_22 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_23 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_24 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_25 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_26 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_27 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_28 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_29 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_30 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_31 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_32 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_33 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_34 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_35 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_36 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_37 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_38 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_39 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_40 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_41 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_42 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_43 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_44 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_45 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_46 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_47 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_48 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_49 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_50 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_51 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_52 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_53 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_54 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_55 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_56 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_57 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_58 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_59 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_60 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_61 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_62 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
p_ci_pipeline_iids_63 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
p_ci_pipelines.external_pull_request_id may be NULL, so the relationship to external_pull_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F040p_ci_pipelines auto_canceled_by_partition_id, auto_canceled_by_idfk-nullable Nullable foreign key
p_ci_pipelines.auto_canceled_by_partition_id.auto_canceled_by_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
p_ci_pipelines.pipeline_schedule_id may be NULL, so the relationship to ci_pipeline_schedules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
p_ci_pipelines.ci_ref_id may be NULL, so the relationship to ci_refs is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_pipelines ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_pipelines ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
committed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_pipelines ALTER COLUMN committed_at TYPE timestamptz;
TIMESTAMP without time zone
started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_pipelines ALTER COLUMN started_at TYPE timestamptz;
TIMESTAMP without time zone
finished_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_pipelines ALTER COLUMN finished_at TYPE timestamptz;
Wide table (32 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F945p_ci_pipelines external_pull_request_id, pipeline_schedule_id, ci_ref_idexclusive-arc Either/or foreign keys without a CHECK
p_ci_pipelines has several nullable FKs (external_pull_request_id, pipeline_schedule_id, ci_ref_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE p_ci_pipelines ADD CONSTRAINT p_ci_pipelines_one_target CHECK ((external_pull_request_id IS NOT NULL)::int + (pipeline_schedule_id IS NOT NULL)::int + (ci_ref_id IS NOT NULL)::int = 1);
Isolated table
p_ci_runtime_environments references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
p_ci_stages.partition_id.pipeline_id may be NULL, so the relationship to p_ci_pipelines is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_stages ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE p_ci_stages ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
p_ci_workload_variable_inclusions.partition_id.workload_id may be NULL, so the relationship to p_ci_workloads is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
p_knowledge_graph_code_indexing_tasks references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
p_sent_notifications.issue_email_participant_id may be NULL, so the relationship to issue_email_participants is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_build_infos.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_composer_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_composer_packages.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
packages_conan_file_metadata has several nullable FKs (project_id, package_revision_id, package_reference_id, recipe_revision_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE packages_conan_file_metadata ADD CONSTRAINT packages_conan_file_metadata_one_target CHECK ((project_id IS NOT NULL)::int + (package_revision_id IS NOT NULL)::int + (package_reference_id IS NOT NULL)::int + (recipe_revision_id IS NOT NULL)::int = 1);
Nullable foreign key
packages_conan_file_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_conan_file_metadata.package_revision_id may be NULL, so the relationship to packages_conan_package_revisions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_conan_file_metadata.package_reference_id may be NULL, so the relationship to packages_conan_package_references is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_conan_file_metadata.recipe_revision_id may be NULL, so the relationship to packages_conan_recipe_revisions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
packages_conan_jwt_signing_keys references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
packages_conan_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_conan_package_references.recipe_revision_id may be NULL, so the relationship to packages_conan_recipe_revisions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_file_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_group_architectures.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
packages_debian_group_component_files has several nullable FKs (group_id, architecture_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE packages_debian_group_component_files ADD CONSTRAINT packages_debian_group_component_files_one_target CHECK ((group_id IS NOT NULL)::int + (architecture_id IS NOT NULL)::int = 1);
Nullable foreign key
packages_debian_group_component_files.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_group_component_files.architecture_id may be NULL, so the relationship to packages_debian_group_architectures is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_group_components.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_group_distribution_keys.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_group_distributions.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_project_architectures.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
packages_debian_project_component_files has several nullable FKs (project_id, architecture_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE packages_debian_project_component_files ADD CONSTRAINT packages_debian_project_component_files_one_target CHECK ((project_id IS NOT NULL)::int + (architecture_id IS NOT NULL)::int = 1);
Nullable foreign key
packages_debian_project_component_files.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_project_component_files.architecture_id may be NULL, so the relationship to packages_debian_project_architectures is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_project_components.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_project_distribution_keys.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_project_distributions.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_debian_publications.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_dependencies.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_dependency_links.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_helm_file_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_helm_metadata_cache_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_maven_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_npm_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
packages_npm_metadata_caches references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
packages_nuget_dependency_link_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_nuget_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
packages_nuget_symbol_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
packages_nuget_symbols.package_id may be NULL, so the relationship to packages_packages is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_package_file_build_infos.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
packages_package_file_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
packages_packages.creator_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_pypi_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_rpm_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
packages_rubygems_metadata.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
packages_rubygems_spec_files references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
packages_tags.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
pages_deployment_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
pages_domain_acme_orders.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
pages_domains.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
path_locks has several nullable FKs (project_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE path_locks ADD CONSTRAINT path_locks_one_target CHECK ((project_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE path_locks ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE path_locks ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
path_locks.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
path_locks.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
personal_access_tokens has several nullable FKs (group_id, previous_personal_access_token_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE personal_access_tokens ADD CONSTRAINT personal_access_tokens_one_target CHECK ((group_id IS NOT NULL)::int + (previous_personal_access_token_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE personal_access_tokens ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE personal_access_tokens ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
personal_access_tokens.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
personal_access_tokens.previous_personal_access_token_id may be NULL, so the relationship to personal_access_tokens is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Wide table (103 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F1282plans created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE plans ALTER COLUMN created_at TYPE timestamptz;
F1283plans updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE plans ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
pm_checkpoints references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
pm_cve_enrichment references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
pool_repositories.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
postgres_async_foreign_key_validations references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
postgres_async_indexes references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
postgres_reindex_actions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
postgres_reindex_queued_actions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
programming_languages references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
project_audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
project_compliance_framework_settings.framework_id may be NULL, so the relationship to compliance_management_frameworks is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_compliance_standards_adherence.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_control_compliance_statuses.requirement_status_id may be NULL, so the relationship to project_requirement_compliance_statuses is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
project_data_transfers references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
project_export_jobs.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
jira_dvcs_cloud_last_sync_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_feature_usages ALTER COLUMN jira_dvcs_cloud_last_sync_at TYPE timestamptz;
TIMESTAMP without time zone
jira_dvcs_server_last_sync_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_feature_usages ALTER COLUMN jira_dvcs_server_last_sync_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_features ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_features ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_group_links ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_group_links ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
project_group_links.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_import_export_relation_export_upload_uploads ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
last_update_started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_mirror_data ALTER COLUMN last_update_started_at TYPE timestamptz;
TIMESTAMP without time zone
last_update_scheduled_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_mirror_data ALTER COLUMN last_update_scheduled_at TYPE timestamptz;
TIMESTAMP without time zone
next_execution_timestamp stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_mirror_data ALTER COLUMN next_execution_timestamp TYPE timestamptz;
Nullable foreign key
project_relation_export_uploads.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_relation_exports.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
project_secrets_manager_maintenance_tasks has several nullable FKs (organization_id, project_secrets_manager_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE project_secrets_manager_maintenance_tasks ADD CONSTRAINT project_secrets_manager_maintenance_tasks_one_target CHECK ((organization_id IS NOT NULL)::int + (project_secrets_manager_id IS NOT NULL)::int = 1);
Nullable foreign key
project_secrets_manager_maintenance_tasks.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_secrets_manager_maintenance_tasks.project_secrets_manager_id may be NULL, so the relationship to project_secrets_managers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_secrets_managers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
project_security_exclusions references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
project_security_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1033project_settings pipeline_execution_policy_bot_access_group_id, duo_dependency_bump_breaking_changes_enabled_by_id, push_rule_idexclusive-arc Either/or foreign keys without a CHECK
project_settings has several nullable FKs (pipeline_execution_policy_bot_access_group_id, duo_dependency_bump_breaking_changes_enabled_by_id, push_rule_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE project_settings ADD CONSTRAINT project_settings_one_target CHECK ((pipeline_execution_policy_bot_access_group_id IS NOT NULL)::int + (duo_dependency_bump_breaking_changes_enabled_by_id IS NOT NULL)::int + (push_rule_id IS NOT NULL)::int = 1);
Wide table (73 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
project_settings.pipeline_execution_policy_bot_access_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F568project_settings duo_dependency_bump_breaking_changes_enabled_by_idfk-nullable Nullable foreign key
project_settings.duo_dependency_bump_breaking_changes_enabled_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
project_settings.push_rule_id may be NULL, so the relationship to push_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
project_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
shared_runners_seconds_last_reset stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_statistics ALTER COLUMN shared_runners_seconds_last_reset TYPE timestamptz;
Nullable foreign key
project_statistics.root_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_topic_uploads ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE project_uploads ALTER COLUMN created_at TYPE timestamptz;
F030projects project_namespace_idfk-nullable Nullable foreign key
projects.project_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
projects.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN updated_at TYPE timestamptz;
F1083projects last_activity_attimestamp-tz TIMESTAMP without time zone
last_activity_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN last_activity_at TYPE timestamptz;
F1084projects mirror_last_update_attimestamp-tz TIMESTAMP without time zone
mirror_last_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN mirror_last_update_at TYPE timestamptz;
F1085projects mirror_last_successful_update_attimestamp-tz TIMESTAMP without time zone
mirror_last_successful_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN mirror_last_successful_update_at TYPE timestamptz;
F1086projects last_repository_check_attimestamp-tz TIMESTAMP without time zone
last_repository_check_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN last_repository_check_at TYPE timestamptz;
F1087projects last_repository_updated_attimestamp-tz TIMESTAMP without time zone
last_repository_updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE projects ALTER COLUMN last_repository_updated_at TYPE timestamptz;
Hub table: referenced by 371 tables
Any change to its key, its delete semantics, or its partitioning touches every dependent. Migrations on hub tables need the longest lock windows and the most careful rollout.
Fix Treat schema changes here as breaking changes with a written rollout plan.
Wide table (82 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
F944projects project_namespace_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
projects has several nullable FKs (project_namespace_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE projects ADD CONSTRAINT projects_one_target CHECK ((project_namespace_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
Isolated table
projects_visits references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Either/or foreign keys without a CHECK
protected_branch_merge_access_levels has several nullable FKs (protected_branch_project_id, group_id, member_role_id, protected_branch_namespace_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_branch_merge_access_levels ADD CONSTRAINT protected_branch_merge_access_levels_one_target CHECK ((protected_branch_project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (member_role_id IS NOT NULL)::int + (protected_branch_namespace_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branch_merge_access_levels ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branch_merge_access_levels ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
protected_branch_merge_access_levels.protected_branch_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_merge_access_levels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_merge_access_levels.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_merge_access_levels.protected_branch_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_merge_access_levels.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
protected_branch_push_access_levels has several nullable FKs (deploy_key_id, protected_branch_namespace_id, group_id, member_role_id, protected_branch_project_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_branch_push_access_levels ADD CONSTRAINT protected_branch_push_access_levels_one_target CHECK ((deploy_key_id IS NOT NULL)::int + (protected_branch_namespace_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (member_role_id IS NOT NULL)::int + (protected_branch_project_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branch_push_access_levels ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branch_push_access_levels ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
protected_branch_push_access_levels.deploy_key_id may be NULL, so the relationship to keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_push_access_levels.protected_branch_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_push_access_levels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_push_access_levels.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_push_access_levels.protected_branch_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_push_access_levels.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
protected_branch_unprotect_access_levels has several nullable FKs (protected_branch_project_id, protected_branch_namespace_id, member_role_id, user_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_branch_unprotect_access_levels ADD CONSTRAINT protected_branch_unprotect_access_levels_one_target CHECK ((protected_branch_project_id IS NOT NULL)::int + (protected_branch_namespace_id IS NOT NULL)::int + (member_role_id IS NOT NULL)::int + (user_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Nullable foreign key
protected_branch_unprotect_access_levels.protected_branch_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_unprotect_access_levels.protected_branch_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_unprotect_access_levels.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_unprotect_access_levels.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branch_unprotect_access_levels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branches ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_branches ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
protected_branches.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_branches.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
protected_environment_approval_rules has several nullable FKs (protected_environment_group_id, group_id, user_id, protected_environment_project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_environment_approval_rules ADD CONSTRAINT protected_environment_approval_rules_one_target CHECK ((protected_environment_group_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (user_id IS NOT NULL)::int + (protected_environment_project_id IS NOT NULL)::int = 1);
Nullable foreign key
protected_environment_approval_rules.protected_environment_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_approval_rules.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_approval_rules.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_approval_rules.protected_environment_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
protected_environment_deploy_access_levels has several nullable FKs (protected_environment_group_id, protected_environment_project_id, group_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_environment_deploy_access_levels ADD CONSTRAINT protected_environment_deploy_access_levels_one_target CHECK ((protected_environment_group_id IS NOT NULL)::int + (protected_environment_project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
protected_environment_deploy_access_levels.protected_environment_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_deploy_access_levels.protected_environment_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_deploy_access_levels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environment_deploy_access_levels.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environments.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_environments.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
protected_tag_create_access_levels has several nullable FKs (deploy_key_id, project_id, group_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE protected_tag_create_access_levels ADD CONSTRAINT protected_tag_create_access_levels_one_target CHECK ((deploy_key_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_tag_create_access_levels ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_tag_create_access_levels ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
protected_tag_create_access_levels.deploy_key_id may be NULL, so the relationship to keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_tag_create_access_levels.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_tag_create_access_levels.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
protected_tag_create_access_levels.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_tags ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE protected_tags ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
push_event_payloads.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE push_rules ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE push_rules ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
push_rules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE redirect_routes ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE redirect_routes ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
redirect_routes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
related_epic_links has several nullable FKs (group_id, issue_link_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE related_epic_links ADD CONSTRAINT related_epic_links_one_target CHECK ((group_id IS NOT NULL)::int + (issue_link_id IS NOT NULL)::int = 1);
Nullable foreign key
related_epic_links.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
related_epic_links.issue_link_id may be NULL, so the relationship to issue_links is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
release_links.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1041releases project_id, author_idexclusive-arc Either/or foreign keys without a CHECK
releases has several nullable FKs (project_id, author_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE releases ADD CONSTRAINT releases_one_target CHECK ((project_id IS NOT NULL)::int + (author_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE releases ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE releases ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
releases.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
releases.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
last_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE remote_mirrors ALTER COLUMN last_update_at TYPE timestamptz;
TIMESTAMP without time zone
last_successful_update_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE remote_mirrors ALTER COLUMN last_successful_update_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE remote_mirrors ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE remote_mirrors ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
last_update_started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE remote_mirrors ALTER COLUMN last_update_started_at TYPE timestamptz;
Nullable foreign key
remote_mirrors.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
required_code_owners_sections.protected_branch_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
required_code_owners_sections.protected_branch_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
requirements.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
requirements_management_test_reports has several nullable FKs (project_id, issue_id, author_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE requirements_management_test_reports ADD CONSTRAINT requirements_management_test_reports_one_target CHECK ((project_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (author_id IS NOT NULL)::int = 1);
Nullable foreign key
requirements_management_test_reports.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
requirements_management_test_reports.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
requirements_management_test_reports.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
resource_iteration_events has several nullable FKs (triggered_by_id, merge_request_id, issue_id, iteration_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_iteration_events ADD CONSTRAINT resource_iteration_events_one_target CHECK ((triggered_by_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (iteration_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_iteration_events.triggered_by_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_iteration_events.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_iteration_events.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_iteration_events.iteration_id may be NULL, so the relationship to sprints is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
resource_label_events has several nullable FKs (issue_id, epic_id, merge_request_id, label_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_label_events ADD CONSTRAINT resource_label_events_one_target CHECK ((issue_id IS NOT NULL)::int + (epic_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int + (label_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_label_events.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_label_events.epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_label_events.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_label_events.label_id may be NULL, so the relationship to labels is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_label_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
resource_link_events has several nullable FKs (system_note_metadata_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_link_events ADD CONSTRAINT resource_link_events_one_target CHECK ((system_note_metadata_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_link_events.system_note_metadata_id may be NULL, so the relationship to system_note_metadata is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_link_events.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
resource_milestone_events has several nullable FKs (merge_request_id, issue_id, milestone_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_milestone_events ADD CONSTRAINT resource_milestone_events_one_target CHECK ((merge_request_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (milestone_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_milestone_events.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_milestone_events.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_milestone_events.milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_milestone_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1047resource_state_events issue_id, merge_request_id, source_merge_request_id, epic_id, user_idexclusive-arc Either/or foreign keys without a CHECK
resource_state_events has several nullable FKs (issue_id, merge_request_id, source_merge_request_id, epic_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_state_events ADD CONSTRAINT resource_state_events_one_target CHECK ((issue_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int + (source_merge_request_id IS NOT NULL)::int + (epic_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_state_events.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_state_events.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_state_events.source_merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_state_events.epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_state_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
resource_weight_events has several nullable FKs (namespace_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE resource_weight_events ADD CONSTRAINT resource_weight_events_one_target CHECK ((namespace_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
resource_weight_events.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
resource_weight_events.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
reviews.author_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1198routes created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE routes ALTER COLUMN created_at TYPE timestamptz;
F1199routes updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE routes ALTER COLUMN updated_at TYPE timestamptz;
F345routes namespace_idfk-nullable Nullable foreign key
routes.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
saml_group_links.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
saml_providers.member_role_id may be NULL, so the relationship to member_roles is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1049saved_views created_by_id, updated_by_idexclusive-arc Either/or foreign keys without a CHECK
saved_views has several nullable FKs (created_by_id, updated_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE saved_views ADD CONSTRAINT saved_views_one_target CHECK ((created_by_id IS NOT NULL)::int + (updated_by_id IS NOT NULL)::int = 1);
Nullable foreign key
saved_views.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
saved_views.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1050sbom_occurrences component_version_id, source_package_id, source_idexclusive-arc Either/or foreign keys without a CHECK
sbom_occurrences has several nullable FKs (component_version_id, source_package_id, source_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE sbom_occurrences ADD CONSTRAINT sbom_occurrences_one_target CHECK ((component_version_id IS NOT NULL)::int + (source_package_id IS NOT NULL)::int + (source_id IS NOT NULL)::int = 1);
Nullable foreign key
sbom_occurrences.component_version_id may be NULL, so the relationship to sbom_component_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sbom_occurrences.source_package_id may be NULL, so the relationship to sbom_source_packages is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sbom_occurrences.source_id may be NULL, so the relationship to sbom_sources is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sbom_occurrences_vulnerabilities.sbom_occurrence_ref_id may be NULL, so the relationship to sbom_occurrence_refs is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sbom_vulnerability_scans.sbom_vulnerability_scan_result_id may be NULL, so the relationship to sbom_vulnerability_scan_results is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
scan_result_policies has several nullable FKs (approval_policy_rule_id, project_id, namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE scan_result_policies ADD CONSTRAINT scan_result_policies_one_target CHECK ((approval_policy_rule_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int = 1);
Nullable foreign key
scan_result_policies.approval_policy_rule_id may be NULL, so the relationship to approval_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
scan_result_policies.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
scan_result_policies.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
scan_result_policy_violations.approval_policy_rule_id may be NULL, so the relationship to approval_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
scan_result_policy_violations.scan_result_policy_id may be NULL, so the relationship to scan_result_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
schema_migrations references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
scim_identities.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
scim_oauth_access_tokens has several nullable FKs (organization_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE scim_oauth_access_tokens ADD CONSTRAINT scim_oauth_access_tokens_one_target CHECK ((organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
Nullable foreign key
scim_oauth_access_tokens.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
scim_oauth_access_tokens.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
secrets_management_recovery_keys references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
security_finding_enrichments.vulnerability_id may be NULL, so the relationship to vulnerabilities is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
security_finding_token_statuses references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
security_inventory_filters references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
security_orchestration_policy_configurations.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_orchestration_policy_configurations.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
security_orchestration_policy_rule_schedules has several nullable FKs (namespace_id, project_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE security_orchestration_policy_rule_schedules ADD CONSTRAINT security_orchestration_policy_rule_schedules_one_target CHECK ((namespace_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
security_orchestration_policy_rule_schedules.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_orchestration_policy_rule_schedules.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_orchestration_policy_rule_schedules.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
security_policy_dismissals has several nullable FKs (security_policy_id, user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE security_policy_dismissals ADD CONSTRAINT security_policy_dismissals_one_target CHECK ((security_policy_id IS NOT NULL)::int + (user_id IS NOT NULL)::int = 1);
Nullable foreign key
security_policy_dismissals.security_policy_id may be NULL, so the relationship to security_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_policy_dismissals.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_policy_settings.csp_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
security_scan_profile_triggers.security_scan_profile_configuration_id may be NULL, so the relationship to security_scan_profile_configurations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sentry_issues.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
service_access_tokens references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
service_desk_custom_email_verifications.triggerer_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
service_desk_settings.file_template_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_api_scopes.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1055slack_integrations project_id, group_id, integration_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
slack_integrations has several nullable FKs (project_id, group_id, integration_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE slack_integrations ADD CONSTRAINT slack_integrations_one_target CHECK ((project_id IS NOT NULL)::int + (group_id IS NOT NULL)::int + (integration_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE slack_integrations ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE slack_integrations ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
slack_integrations.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations.integration_id may be NULL, so the relationship to integrations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations_scopes.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations_scopes.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
slack_integrations_scopes.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repositories.snippet_organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repositories.snippet_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repository_states.snippet_organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repository_states.snippet_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repository_storage_moves.snippet_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_repository_storage_moves.snippet_organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_statistics.snippet_organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_statistics.snippet_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE snippet_uploads ALTER COLUMN created_at TYPE timestamptz;
Either/or foreign keys without a CHECK
snippet_user_mentions has several nullable FKs (snippet_project_id, snippet_organization_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE snippet_user_mentions ADD CONSTRAINT snippet_user_mentions_one_target CHECK ((snippet_project_id IS NOT NULL)::int + (snippet_organization_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
Nullable foreign key
snippet_user_mentions.snippet_project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_user_mentions.snippet_organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
snippet_user_mentions.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE snippets ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE snippets ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
snippets.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
software_license_policies has several nullable FKs (custom_software_license_id, approval_policy_rule_id, scan_result_policy_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE software_license_policies ADD CONSTRAINT software_license_policies_one_target CHECK ((custom_software_license_id IS NOT NULL)::int + (approval_policy_rule_id IS NOT NULL)::int + (scan_result_policy_id IS NOT NULL)::int = 1);
Nullable foreign key
software_license_policies.custom_software_license_id may be NULL, so the relationship to custom_software_licenses is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
software_license_policies.approval_policy_rule_id may be NULL, so the relationship to approval_policy_rules is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
software_license_policies.scan_result_policy_id may be NULL, so the relationship to scan_result_policies is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1058spam_logs user_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
spam_logs has several nullable FKs (user_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE spam_logs ADD CONSTRAINT spam_logs_one_target CHECK ((user_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE spam_logs ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE spam_logs ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
spam_logs.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
spam_logs.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1059sprints iterations_cadence_id, group_idexclusive-arc Either/or foreign keys without a CHECK
sprints has several nullable FKs (iterations_cadence_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE sprints ADD CONSTRAINT sprints_one_target CHECK ((iterations_cadence_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
F693sprints iterations_cadence_idfk-nullable Nullable foreign key
sprints.iterations_cadence_id may be NULL, so the relationship to iterations_cadences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
sprints.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
ssh_signatures has several nullable FKs (user_id, key_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE ssh_signatures ADD CONSTRAINT ssh_signatures_one_target CHECK ((user_id IS NOT NULL)::int + (key_id IS NOT NULL)::int = 1);
Nullable foreign key
ssh_signatures.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
ssh_signatures.key_id may be NULL, so the relationship to keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
status_check_responses.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
status_page_published_incidents.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
subscription_add_on_purchases.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
subscription_seat_assignments.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
subscription_user_add_on_assignments.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
subscriptions has several nullable FKs (user_id, project_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE subscriptions ADD CONSTRAINT subscriptions_one_target CHECK ((user_id IS NOT NULL)::int + (project_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE subscriptions ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE subscriptions ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
subscriptions.user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
subscriptions.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
suggestions.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
supply_chain_attestation_states.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
system_access_group_microsoft_graph_access_tokens.system_access_group_microsoft_application_id may be NULL, so the relationship to system_access_group_microsoft_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
system_access_microsoft_applications.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
system_access_microsoft_graph_access_tokens.system_access_microsoft_application_id may be NULL, so the relationship to system_access_microsoft_applications is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
system_note_metadata has several nullable FKs (namespace_id, description_version_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE system_note_metadata ADD CONSTRAINT system_note_metadata_one_target CHECK ((namespace_id IS NOT NULL)::int + (description_version_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE system_note_metadata ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE system_note_metadata ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
system_note_metadata.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
system_note_metadata.description_version_id may be NULL, so the relationship to description_versions is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
tag_gpg_signatures has several nullable FKs (gpg_key_subkey_id, gpg_key_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE tag_gpg_signatures ADD CONSTRAINT tag_gpg_signatures_one_target CHECK ((gpg_key_subkey_id IS NOT NULL)::int + (gpg_key_id IS NOT NULL)::int = 1);
Nullable foreign key
tag_gpg_signatures.gpg_key_subkey_id may be NULL, so the relationship to gpg_key_subkeys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
tag_gpg_signatures.gpg_key_id may be NULL, so the relationship to gpg_keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
tag_ssh_signatures.key_id may be NULL, so the relationship to keys is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
tags references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
terraform_state_version_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Either/or foreign keys without a CHECK
terraform_state_versions has several nullable FKs (project_id, created_by_user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE terraform_state_versions ADD CONSTRAINT terraform_state_versions_one_target CHECK ((project_id IS NOT NULL)::int + (created_by_user_id IS NOT NULL)::int = 1);
Nullable foreign key
terraform_state_versions.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
terraform_state_versions.created_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
terraform_states.locked_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1065timelogs project_id, timelog_category_id, issue_id, merge_request_id, note_idexclusive-arc Either/or foreign keys without a CHECK
timelogs has several nullable FKs (project_id, timelog_category_id, issue_id, merge_request_id, note_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE timelogs ADD CONSTRAINT timelogs_one_target CHECK ((project_id IS NOT NULL)::int + (timelog_category_id IS NOT NULL)::int + (issue_id IS NOT NULL)::int + (merge_request_id IS NOT NULL)::int + (note_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE timelogs ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE timelogs ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
spent_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE timelogs ALTER COLUMN spent_at TYPE timestamptz;
Nullable foreign key
timelogs.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F718timelogs timelog_category_idfk-nullable Nullable foreign key
timelogs.timelog_category_id may be NULL, so the relationship to timelog_categories is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
timelogs.issue_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F720timelogs merge_request_idfk-nullable Nullable foreign key
timelogs.merge_request_id may be NULL, so the relationship to merge_requests is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
timelogs.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1066todos project_id, organization_id, note_id, group_idexclusive-arc Either/or foreign keys without a CHECK
todos has several nullable FKs (project_id, organization_id, note_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE todos ADD CONSTRAINT todos_one_target CHECK ((project_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (note_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
F1330todos created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE todos ALTER COLUMN created_at TYPE timestamptz;
F1331todos updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE todos ALTER COLUMN updated_at TYPE timestamptz;
F722todos project_idfk-nullable Nullable foreign key
todos.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F723todos organization_idfk-nullable Nullable foreign key
todos.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F724todos note_idfk-nullable Nullable foreign key
todos.note_id may be NULL, so the relationship to notes is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F725todos group_idfk-nullable Nullable foreign key
todos.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
upcoming_reconciliations.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
upload_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F055uploads uploaded_by_user_idfk-nullable Nullable foreign key
uploads.uploaded_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
uploads.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F057uploads namespace_idfk-nullable Nullable foreign key
uploads.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F058uploads organization_idfk-nullable Nullable foreign key
uploads.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1122uploads created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE uploads ALTER COLUMN created_at TYPE timestamptz;
F948uploads uploaded_by_user_id, project_id, namespace_id, organization_idexclusive-arc Either/or foreign keys without a CHECK
uploads has several nullable FKs (uploaded_by_user_id, project_id, namespace_id, organization_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE uploads ADD CONSTRAINT uploads_one_target CHECK ((uploaded_by_user_id IS NOT NULL)::int + (project_id IS NOT NULL)::int + (namespace_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int = 1);
F1067user_achievements namespace_id, awarded_by_user_id, revoked_by_user_idexclusive-arc Either/or foreign keys without a CHECK
user_achievements has several nullable FKs (namespace_id, awarded_by_user_id, revoked_by_user_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE user_achievements ADD CONSTRAINT user_achievements_one_target CHECK ((namespace_id IS NOT NULL)::int + (awarded_by_user_id IS NOT NULL)::int + (revoked_by_user_id IS NOT NULL)::int = 1);
Nullable foreign key
user_achievements.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_achievements.awarded_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_achievements.revoked_by_user_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_agent_details ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_agent_details ALTER COLUMN updated_at TYPE timestamptz;
Nullable foreign key
user_agent_details.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
user_audit_events references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_custom_attributes ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_custom_attributes ALTER COLUMN updated_at TYPE timestamptz;
Wide table (30 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
user_details.bot_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_group_member_roles.shared_with_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_permission_export_upload_uploads ALTER COLUMN created_at TYPE timestamptz;
F1068user_preferences default_duo_add_on_assignment_id, duo_default_namespace_id, knowledge_graph_governing_namespace_idexclusive-arc Either/or foreign keys without a CHECK
user_preferences has several nullable FKs (default_duo_add_on_assignment_id, duo_default_namespace_id, knowledge_graph_governing_namespace_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE user_preferences ADD CONSTRAINT user_preferences_one_target CHECK ((default_duo_add_on_assignment_id IS NOT NULL)::int + (duo_default_namespace_id IS NOT NULL)::int + (knowledge_graph_governing_namespace_id IS NOT NULL)::int = 1);
Wide table (58 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
user_preferences.default_duo_add_on_assignment_id may be NULL, so the relationship to subscription_user_add_on_assignments is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_preferences.duo_default_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_preferences.knowledge_graph_governing_namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
user_project_member_roles.shared_with_group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE user_uploads ALTER COLUMN created_at TYPE timestamptz;
F1088users reset_password_sent_attimestamp-tz TIMESTAMP without time zone
reset_password_sent_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN reset_password_sent_at TYPE timestamptz;
F1089users remember_created_attimestamp-tz TIMESTAMP without time zone
remember_created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN remember_created_at TYPE timestamptz;
F1090users current_sign_in_attimestamp-tz TIMESTAMP without time zone
current_sign_in_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN current_sign_in_at TYPE timestamptz;
F1091users last_sign_in_attimestamp-tz TIMESTAMP without time zone
last_sign_in_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN last_sign_in_at TYPE timestamptz;
F1092users created_attimestamp-tz TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN created_at TYPE timestamptz;
F1093users updated_attimestamp-tz TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN updated_at TYPE timestamptz;
F1094users locked_attimestamp-tz TIMESTAMP without time zone
locked_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN locked_at TYPE timestamptz;
F1095users password_expires_attimestamp-tz TIMESTAMP without time zone
password_expires_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN password_expires_at TYPE timestamptz;
F1096users last_credential_check_attimestamp-tz TIMESTAMP without time zone
last_credential_check_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN last_credential_check_at TYPE timestamptz;
F1097users confirmed_attimestamp-tz TIMESTAMP without time zone
confirmed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN confirmed_at TYPE timestamptz;
F1098users confirmation_sent_attimestamp-tz TIMESTAMP without time zone
confirmation_sent_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN confirmation_sent_at TYPE timestamptz;
F1099users admin_email_unsubscribed_attimestamp-tz TIMESTAMP without time zone
admin_email_unsubscribed_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN admin_email_unsubscribed_at TYPE timestamptz;
F1100users otp_grace_period_started_attimestamp-tz TIMESTAMP without time zone
otp_grace_period_started_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users ALTER COLUMN otp_grace_period_started_at TYPE timestamptz;
Hub table: referenced by 201 tables
Any change to its key, its delete semantics, or its partitioning touches every dependent. Migrations on hub tables need the longest lock windows and the most careful rollout.
Fix Treat schema changes here as breaking changes with a written rollout plan.
Wide table (78 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users_star_projects ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE users_star_projects ALTER COLUMN updated_at TYPE timestamptz;
Isolated table
users_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
value_stream_dashboard_counts references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
verification_codes references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_container_cache_remote_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_local_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_maven_cache_remote_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
virtual_registries_packages_maven_registry_upstreams.upstream_id may be NULL, so the relationship to virtual_registries_packages_maven_upstreams is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
virtual_registries_packages_maven_registry_upstreams.local_upstream_id may be NULL, so the relationship to virtual_registries_packages_maven_local_upstreams is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
virtual_registries_packages_npm_cache_local_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_local_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_00 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_01 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_02 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_03 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_04 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_05 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_06 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_07 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_08 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_09 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_10 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_11 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_12 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_13 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_14 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
virtual_registries_packages_npm_cache_remote_entries_15 references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
vulnerabilities.finding_id may be NULL, so the relationship to vulnerability_occurrences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE vulnerability_archive_export_uploads ALTER COLUMN created_at TYPE timestamptz;
Isolated table
vulnerability_archive_exports references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
vulnerability_archived_records references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
vulnerability_archives references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE vulnerability_export_part_uploads ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE vulnerability_export_uploads ALTER COLUMN created_at TYPE timestamptz;
Nullable foreign key
vulnerability_external_issue_links.vulnerability_occurrence_id may be NULL, so the relationship to vulnerability_occurrences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
vulnerability_feedback references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Either/or foreign keys without a CHECK
vulnerability_findings_remediations has several nullable FKs (vulnerability_occurrence_id, vulnerability_remediation_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE vulnerability_findings_remediations ADD CONSTRAINT vulnerability_findings_remediations_one_target CHECK ((vulnerability_occurrence_id IS NOT NULL)::int + (vulnerability_remediation_id IS NOT NULL)::int = 1);
Nullable foreign key
vulnerability_findings_remediations.vulnerability_occurrence_id may be NULL, so the relationship to vulnerability_occurrences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
vulnerability_findings_remediations.vulnerability_remediation_id may be NULL, so the relationship to vulnerability_remediations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
vulnerability_historical_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
vulnerability_namespace_historical_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Isolated table
vulnerability_namespace_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
vulnerability_occurrence_identifiers.partition_id.identifier_id may be NULL, so the relationship to vulnerability_identifiers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
vulnerability_occurrences.vulnerability_id may be NULL, so the relationship to vulnerabilities is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
vulnerability_occurrences.partition_id.primary_identifier_id may be NULL, so the relationship to vulnerability_identifiers is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
vulnerability_reads.vulnerability_occurrence_id may be NULL, so the relationship to vulnerability_occurrences is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE vulnerability_remediation_uploads ALTER COLUMN created_at TYPE timestamptz;
Isolated table
vulnerability_statistics references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE web_hook_logs_daily ALTER COLUMN updated_at TYPE timestamptz;
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE web_hook_logs_daily ALTER COLUMN created_at TYPE timestamptz;
Isolated table
web_hook_logs_daily references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
F1070web_hooks project_id, integration_id, organization_id, group_idexclusive-arc Either/or foreign keys without a CHECK
web_hooks has several nullable FKs (project_id, integration_id, organization_id, group_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE web_hooks ADD CONSTRAINT web_hooks_one_target CHECK ((project_id IS NOT NULL)::int + (integration_id IS NOT NULL)::int + (organization_id IS NOT NULL)::int + (group_id IS NOT NULL)::int = 1);
TIMESTAMP without time zone
created_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE web_hooks ALTER COLUMN created_at TYPE timestamptz;
TIMESTAMP without time zone
updated_at stores wall-clock time with no zone. It reads back differently depending on the session's TimeZone, and DST transitions produce ambiguous values.
Fix Use TIMESTAMPTZ.
ALTER TABLE web_hooks ALTER COLUMN updated_at TYPE timestamptz;
Wide table (49 columns)
Tables this wide usually hide several entities (or a JSON column that wants to be one). Every row update rewrites the whole tuple; TOAST kicks in; indexes bloat.
Fix Look for column groups that always change together and split them out.
Nullable foreign key
web_hooks.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
web_hooks.integration_id may be NULL, so the relationship to integrations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
web_hooks.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
web_hooks.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
wiki_page_meta.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
wiki_page_meta.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
wiki_page_slugs.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
wiki_page_slugs.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
wiki_repository_states references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.
Nullable foreign key
work_item_current_statuses.custom_status_id may be NULL, so the relationship to work_item_custom_statuses is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
work_item_custom_lifecycles has several nullable FKs (updated_by_id, created_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE work_item_custom_lifecycles ADD CONSTRAINT work_item_custom_lifecycles_one_target CHECK ((updated_by_id IS NOT NULL)::int + (created_by_id IS NOT NULL)::int = 1);
Nullable foreign key
work_item_custom_lifecycles.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_custom_lifecycles.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
work_item_custom_statuses has several nullable FKs (updated_by_id, created_by_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE work_item_custom_statuses ADD CONSTRAINT work_item_custom_statuses_one_target CHECK ((updated_by_id IS NOT NULL)::int + (created_by_id IS NOT NULL)::int = 1);
Nullable foreign key
work_item_custom_statuses.updated_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_custom_statuses.created_by_id may be NULL, so the relationship to users is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_custom_types.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_custom_types.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1073work_item_dates_sources start_date_sourcing_milestone_id, start_date_sourcing_work_item_id, due_date_sourcing_work_item_id, due_date_sourcing_milestone_idexclusive-arc Either/or foreign keys without a CHECK
work_item_dates_sources has several nullable FKs (start_date_sourcing_milestone_id, start_date_sourcing_work_item_id, due_date_sourcing_work_item_id, due_date_sourcing_milestone_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE work_item_dates_sources ADD CONSTRAINT work_item_dates_sources_one_target CHECK ((start_date_sourcing_milestone_id IS NOT NULL)::int + (start_date_sourcing_work_item_id IS NOT NULL)::int + (due_date_sourcing_work_item_id IS NOT NULL)::int + (due_date_sourcing_milestone_id IS NOT NULL)::int = 1);
Nullable foreign key
work_item_dates_sources.start_date_sourcing_milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_dates_sources.start_date_sourcing_work_item_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_dates_sources.due_date_sourcing_work_item_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_dates_sources.due_date_sourcing_milestone_id may be NULL, so the relationship to milestones is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_parent_links.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_progresses.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_settings.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_settings.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Either/or foreign keys without a CHECK
work_item_transitions has several nullable FKs (promoted_to_epic_id, duplicated_to_id, moved_to_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE work_item_transitions ADD CONSTRAINT work_item_transitions_one_target CHECK ((promoted_to_epic_id IS NOT NULL)::int + (duplicated_to_id IS NOT NULL)::int + (moved_to_id IS NOT NULL)::int = 1);
Nullable foreign key
work_item_transitions.promoted_to_epic_id may be NULL, so the relationship to epics is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_transitions.duplicated_to_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_transitions.moved_to_id may be NULL, so the relationship to issues is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_type_visibility_defaults.namespace_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
work_item_type_visibility_defaults.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
workspace_variables.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F776workspaces personal_access_token_idfk-nullable Nullable foreign key
workspaces.personal_access_token_id may be NULL, so the relationship to personal_access_tokens is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
x509_certificates.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
x509_issuers.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
zentao_tracker_data.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
zentao_tracker_data.group_id may be NULL, so the relationship to namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
zentao_tracker_data.organization_id may be NULL, so the relationship to organizations is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
F1075zoekt_indices zoekt_enabled_namespace_id, zoekt_replica_idexclusive-arc Either/or foreign keys without a CHECK
zoekt_indices has several nullable FKs (zoekt_enabled_namespace_id, zoekt_replica_id) that look like an exclusive arc — a row should point at exactly one of them. Nothing stops zero or both.
Fix Add a CHECK that exactly one is non-null, or restructure with a supertype.
ALTER TABLE zoekt_indices ADD CONSTRAINT zoekt_indices_one_target CHECK ((zoekt_enabled_namespace_id IS NOT NULL)::int + (zoekt_replica_id IS NOT NULL)::int = 1);
Nullable foreign key
zoekt_indices.zoekt_enabled_namespace_id may be NULL, so the relationship to zoekt_enabled_namespaces is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
zoekt_indices.zoekt_replica_id may be NULL, so the relationship to zoekt_replicas is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Nullable foreign key
zoekt_repositories.project_id may be NULL, so the relationship to projects is optional. That is legitimate (e.g. approved_by before approval) but often a modelling shrug: a row with no owner, or two nullable FKs that are secretly an either/or.
Fix Confirm the optionality is a domain rule; document it in the column comment.
Isolated table
zoekt_tasks references nothing and nothing references it. Either it is a staging/log table (fine, say so), or it is dead, or it is the seed of a second data model growing beside the first.
Fix Document its purpose or drop it.