Skip to content

Commit

Permalink
Add check "Tables are not linked to other tables" (#469)
Browse files Browse the repository at this point in the history
* Add TablesNotLinkedToOthersCheckOnHost

* Add check on cluster and logger

* Add new bean to the starter
  • Loading branch information
mfvanek authored Oct 22, 2024
1 parent 92254d1 commit 4bdb88d
Show file tree
Hide file tree
Showing 15 changed files with 301 additions and 202 deletions.
51 changes: 26 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,32 @@ All checks can be divided into 2 groups:

**pg-index-health** allows you to detect the following problems:

|| Description | Type | SQL query |
|----|------------------------------------------------------------------------------------------------------------------------------------|--------------------|-----------------------------------------------------------------------------------------------------------|
| 1 | Invalid (broken) indexes | **runtime**/static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/invalid_indexes.sql) |
| 1 | Duplicated (completely identical) indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/duplicated_indexes.sql) |
| 3 | Intersected (partially identical) indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/intersected_indexes.sql) |
| 4 | Unused indexes | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/unused_indexes.sql) |
| 5 | Foreign keys without associated indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/foreign_keys_without_index.sql) |
| 6 | Indexes with null values | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/indexes_with_null_values.sql) |
| 7 | Tables with missing indexes | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_with_missing_indexes.sql) |
| 8 | Tables without primary key | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_without_primary_key.sql) |
| 9 | Indexes [bloat](https://www.percona.com/blog/2018/08/06/basic-understanding-bloat-vacuum-postgresql-mvcc/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/bloated_indexes.sql) |
| 10 | Tables [bloat](https://www.percona.com/blog/2018/08/06/basic-understanding-bloat-vacuum-postgresql-mvcc/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/bloated_tables.sql) |
| 11 | Tables without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_without_description.sql) |
| 12 | Columns without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_without_description.sql) |
| 13 | Columns with [json](https://www.postgresql.org/docs/current/datatype-json.html) type | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_with_json_type.sql) |
| 14 | Columns of [serial types](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL) that are not primary keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_with_serial_types.sql) |
| 15 | Functions without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/functions_without_description.sql) |
| 16 | Indexes [with boolean](https://habr.com/ru/companies/tensor/articles/488104/) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/indexes_with_boolean.sql) |
| 17 | Tables with [not valid constraints](https://habr.com/ru/articles/800121/) | **runtime**/static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/not_valid_constraints.sql) |
| 18 | B-tree indexes [on array columns](https://habr.com/ru/articles/800121/) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/btree_indexes_on_array_columns.sql) |
| 19 | [Sequence overflow](https://habr.com/ru/articles/800121/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/sequence_overflow.sql) |
| 20 | Primary keys with [serial types](https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_serial) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/primary_keys_with_serial_types.sql) |
| 21 | Duplicated ([completely identical](https://habr.com/ru/articles/803841/)) foreign keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/duplicated_foreign_keys.sql) |
| 22 | Intersected ([partially identical](https://habr.com/ru/articles/803841/)) foreign keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/intersected_foreign_keys.sql) |
| 23 | Possible object name overflow (identifiers with maximum length). | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/possible_object_name_overflow.sql) |
|| Description | Type | SQL query |
|----|-------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|-----------------------------------------------------------------------------------------------------------|
| 1 | Invalid (broken) indexes | **runtime**/static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/invalid_indexes.sql) |
| 1 | Duplicated (completely identical) indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/duplicated_indexes.sql) |
| 3 | Intersected (partially identical) indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/intersected_indexes.sql) |
| 4 | Unused indexes | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/unused_indexes.sql) |
| 5 | Foreign keys without associated indexes | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/foreign_keys_without_index.sql) |
| 6 | Indexes with null values | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/indexes_with_null_values.sql) |
| 7 | Tables with missing indexes | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_with_missing_indexes.sql) |
| 8 | Tables without primary key | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_without_primary_key.sql) |
| 9 | Indexes [bloat](https://www.percona.com/blog/2018/08/06/basic-understanding-bloat-vacuum-postgresql-mvcc/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/bloated_indexes.sql) |
| 10 | Tables [bloat](https://www.percona.com/blog/2018/08/06/basic-understanding-bloat-vacuum-postgresql-mvcc/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/bloated_tables.sql) |
| 11 | Tables without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_without_description.sql) |
| 12 | Columns without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_without_description.sql) |
| 13 | Columns with [json](https://www.postgresql.org/docs/current/datatype-json.html) type | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_with_json_type.sql) |
| 14 | Columns of [serial types](https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL) that are not primary keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/columns_with_serial_types.sql) |
| 15 | Functions without [description](https://www.postgresql.org/docs/current/sql-comment.html) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/functions_without_description.sql) |
| 16 | Indexes [with boolean](https://habr.com/ru/companies/tensor/articles/488104/) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/indexes_with_boolean.sql) |
| 17 | Tables with [not valid constraints](https://habr.com/ru/articles/800121/) | **runtime**/static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/not_valid_constraints.sql) |
| 18 | B-tree indexes [on array columns](https://habr.com/ru/articles/800121/) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/btree_indexes_on_array_columns.sql) |
| 19 | [Sequence overflow](https://habr.com/ru/articles/800121/) | **runtime** | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/sequence_overflow.sql) |
| 20 | Primary keys with [serial types](https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_serial) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/primary_keys_with_serial_types.sql) |
| 21 | Duplicated ([completely identical](https://habr.com/ru/articles/803841/)) foreign keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/duplicated_foreign_keys.sql) |
| 22 | Intersected ([partially identical](https://habr.com/ru/articles/803841/)) foreign keys | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/intersected_foreign_keys.sql) |
| 23 | Possible object name overflow (identifiers with maximum length) | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/possible_object_name_overflow.sql) |
| 24 | Tables not linked to other tables | static | [sql](https://github.com/mfvanek/pg-index-health-sql/blob/master/sql/tables_not_linked_to_others.sql) |

For raw sql queries see [pg-index-health-sql](https://github.com/mfvanek/pg-index-health-sql) project.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2019-2024. Ivan Vakhrushev and others.
* https://github.com/mfvanek/pg-index-health
*
* This file is a part of "pg-index-health" - a Java library for
* analyzing and maintaining indexes health in PostgreSQL databases.
*
* Licensed under the Apache License 2.0
*/

package io.github.mfvanek.pg.checks.host;

import io.github.mfvanek.pg.checks.extractors.TableExtractor;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.connection.PgConnection;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.table.Table;

import java.util.List;
import javax.annotation.Nonnull;

/**
* Check for tables that are not linked to other tables on a specific host.
* <p>
* These are often service tables that are not part of the project, or
* tables that are no longer in use or were created by mistake, but were not deleted in a timely manner.
*
* @author Ivan Vahrushev
* @since 0.13.2
*/
public class TablesNotLinkedToOthersCheckOnHost extends AbstractCheckOnHost<Table> {

public TablesNotLinkedToOthersCheckOnHost(@Nonnull final PgConnection pgConnection) {
super(Table.class, pgConnection, Diagnostic.TABLES_NOT_LINKED_TO_OTHERS);
}

/**
* Returns tables that are no longer in use or were created by mistake.
*
* @param pgContext check's context with the specified schema; must not be null
* @return list of tables that are no longer in use or were created by mistake
*/
@Nonnull
@Override
protected List<Table> doCheck(@Nonnull final PgContext pgContext) {
return executeQuery(pgContext, TableExtractor.of());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public enum Diagnostic implements CheckTypeAware {
PRIMARY_KEYS_WITH_SERIAL_TYPES(ExecutionTopology.ON_PRIMARY, "primary_keys_with_serial_types.sql", QueryExecutors::executeQueryWithSchema, false),
DUPLICATED_FOREIGN_KEYS(ExecutionTopology.ON_PRIMARY, "duplicated_foreign_keys.sql", QueryExecutors::executeQueryWithSchema, false),
INTERSECTED_FOREIGN_KEYS(ExecutionTopology.ON_PRIMARY, "intersected_foreign_keys.sql", QueryExecutors::executeQueryWithSchema, false),
POSSIBLE_OBJECT_NAME_OVERFLOW(ExecutionTopology.ON_PRIMARY, "possible_object_name_overflow.sql", QueryExecutors::executeQueryWithSchema, false);
POSSIBLE_OBJECT_NAME_OVERFLOW(ExecutionTopology.ON_PRIMARY, "possible_object_name_overflow.sql", QueryExecutors::executeQueryWithSchema, false),
TABLES_NOT_LINKED_TO_OTHERS(ExecutionTopology.ON_PRIMARY, "tables_not_linked_to_others.sql", QueryExecutors::executeQueryWithSchema, false);

private final ExecutionTopology executionTopology;
private final String sqlQueryFileName;
Expand Down
2 changes: 1 addition & 1 deletion pg-index-health-core/src/main/resources
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-2024. Ivan Vakhrushev and others.
* https://github.com/mfvanek/pg-index-health
*
* This file is a part of "pg-index-health" - a Java library for
* analyzing and maintaining indexes health in PostgreSQL databases.
*
* Licensed under the Apache License 2.0
*/

package io.github.mfvanek.pg.checks.host;

import io.github.mfvanek.pg.common.maintenance.DatabaseCheckOnHost;
import io.github.mfvanek.pg.common.maintenance.Diagnostic;
import io.github.mfvanek.pg.model.PgContext;
import io.github.mfvanek.pg.model.table.Table;
import io.github.mfvanek.pg.support.DatabaseAwareTestBase;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static io.github.mfvanek.pg.support.AbstractCheckOnHostAssert.assertThat;

class TablesNotLinkedToOthersCheckOnHostTest extends DatabaseAwareTestBase {

private final DatabaseCheckOnHost<Table> check = new TablesNotLinkedToOthersCheckOnHost(getPgConnection());

@Test
void shouldSatisfyContract() {
assertThat(check)
.hasType(Table.class)
.hasDiagnostic(Diagnostic.TABLES_NOT_LINKED_TO_OTHERS)
.hasHost(getHost())
.isStatic();
}

@ParameterizedTest
@ValueSource(strings = {PgContext.DEFAULT_SCHEMA_NAME, "custom"})
void onDatabaseWithThem(final String schemaName) {
executeTestOnDatabase(schemaName, dbp -> dbp.withReferences().withMaterializedView().withTableWithoutPrimaryKey(), ctx ->
assertThat(check)
.executing(ctx)
.hasSize(1)
.containsExactly(Table.of(ctx.enrichWithSchema("bad_clients"), 0L)));
}
}
Loading

0 comments on commit 4bdb88d

Please sign in to comment.