Querious Docs

Schema Diagnostics

Scanning a schema for design and maintenance problems.

The Diagnostics subview of Schema Structure checks a schema for common problems, and makes recommendations for you to fix them.

Only you can reallyknow whether something is a problem or not, but using Diagnostics when you inherit a schema from another engineer/source, before a release, or periodically on a busy server, can help point out some issues you might not have otherwise noticed or thought of.

Diagnostics results for a MySQL schema

Scanning #

  1. Click Scan for Issues in the bottom bar to run every check
  2. OR select a check and click Scan at the bottom of its view to run only that one.

The list on the left groups the checks by category, with the number of issues each found. Select a check to see its explanation and the objects it flagged, with details such as the columns or indexes involved.

Each check has a severity:

Severity Meaning
Critical (red) Likely to cause failures or data problems. Fix soon.
Warning (yellow) Costs performance or correctness in some situations.
Advisory (blue) Worth reviewing, but may be intentional.

Scanning only reads the server's catalog and statistics. Nothing is changed, and each issue is yours to fix.

MySQL Checks #

Primary Keys #

Tables Missing Primary Key #

The check: Finds tables with no primary key.

Without one, replication and updates or deletes on those tables are slow or unreliable.

Recommendation: Add a primary key, typically an AUTO_INCREMENT integer column.

Indexes #

Duplicate Indexes #

The check: Finds two indexes on the same columns in the same order.

Both must be updated on every write, so the copy wastes storage and slows writes, with no query benefit.

Recommendation: Drop one of the two.

Redundant Indexes #

The check: Finds a non-unique index that is just the leading part of a longer index.

The longer index already serves the same queries, so the shorter one only adds write cost.

Recommendation: Drop the shorter index, after confirming no query depends on it by name (such as an index hint).

Character Set / Collation #

Tables with Non-Default Charset #

The check: Finds tables whose collation differs from the schema's default.

Mixed collations cause surprising comparisons and can prevent an index from being used.

Recommendation: If it wasn't intentional, convert the table to the schema default with ALTER TABLE ... CONVERT TO CHARACTER SET.

Columns with Non-Default Collation #

The check: Finds columns whose collation differs from their table's.

This has the same problems as above, but within a single table.

Recommendation: If it wasn't intentional, change the column to the table's collation.

Mismatched FK Collations #

The check: Finds foreign keys whose two columns use different collations.

Joins on the relationship must convert values at query time, which loses the use of the index.

Recommendation: Give both columns the same collation.

Tables and Columns using Older utf8 #

The check: Finds tables and columns still using 3-byte utf8 (utf8mb3).

They can't store emoji or other 4-byte characters.

Recommendation: Convert to utf8mb4.

Capacity #

Auto Increment Near Limit #

The check: Finds AUTO_INCREMENT counters at 70% or more of their column type's maximum.

Once the limit is reached, inserts fail.

Recommendation: Change the column to a larger integer type, such as BIGINT UNSIGNED, before it runs out.

Fragmented Tables #

The check: Finds tables where 50 MB or more (and 25% or more) of the table's file is unused space.

The wasted space costs disk and can slow scans.

Recommendation: Run OPTIMIZE TABLE to reclaim it. Note that InnoDB doesn't report space left inside partly empty pages, so this check can miss the most common case.

Storage Engine #

Non-InnoDB Tables #

The check: Finds tables using MyISAM, MEMORY, or another engine besides InnoDB.

These engines lack transactions, row locks, and crash recovery, and MEMORY tables lose their data when the server restarts.

Recommendation: Convert the table to InnoDB, unless the engine is deliberate.

Design #

Floating Point Currency #

The check: Finds FLOAT or DOUBLE columns with names that look like money, such as price, total, or tax.

Binary floating point silently rounds decimal amounts.

Recommendation: Change the column to DECIMAL.

Columns Missing a Foreign Key #

The check: Finds columns like customer_id that match a table and its primary key's type but have no foreign key.

Without a constraint, rows can point at records that don't exist.

Recommendation: Add a foreign key if the column refers to that table. This is a guess based on naming, so ignore columns that refer to outside systems.

Legacy Design #

The check: Finds TIMESTAMP columns, COMPACT or REDUNDANT row formats, and ZEROFILL.

TIMESTAMP stops at the year 2038, the old row formats limit index and value storage, and ZEROFILL is deprecated.

Recommendation: Use DATETIME, the DYNAMIC row format, and pad numbers in your application (or with LPAD) instead of ZEROFILL.

Objects #

Broken Views #

The check: Finds views that reference a table, column, or function that no longer exists.

Any query that uses the view fails.

Recommendation: Redefine the view to use what exists now, or drop it if it's no longer needed.

Objects with a Missing Definer #

The check: Finds views, routines, triggers, and events whose defining user no longer exists. This needs read access to mysql.user.

Using them fails. It often happens after restoring a dump onto another server.

Recommendation: Recreate the object with a definer that exists, or create the missing user.

PostgreSQL Checks #

Tables Missing Primary Key #

The check: Finds tables with no primary key.

Without one, individual rows can't be reliably identified, which complicates updates, deletes, and logical replication.

Recommendation: Add a primary key.

Invalid Indexes #

The check: Finds indexes left invalid, usually by a failed CREATE INDEX CONCURRENTLY.

They're maintained on every write but never used for queries.

Recommendation: Drop the index and create it again.

Sequences Near Max Value #

The check: Finds sequences approaching their maximum value. See Sequences.

Once a sequence reaches its maximum, inserts that use it fail.

Recommendation: Change the column and sequence to a larger type, such as bigint, before it runs out.

Transaction ID Wraparound Risk #

The check: Finds tables nearing the freeze age.

If wraparound is reached, the server stops accepting writes to protect data.

Recommendation: Run VACUUM FREEZE on the table.

Unindexed Foreign Key Columns #

The check: Finds foreign key columns with no index.

Deleting or updating a row in the referenced table has to scan the whole referencing table, and joins on the relationship are slow.

Recommendation: Create an index on the foreign key column.

Duplicate Indexes #

The check: Finds indexes on exactly the same columns as another.

Both must be updated on every write, wasting storage and slowing writes, with no query benefit.

Recommendation: Drop one of the two.

Redundant Indexes #

The check: Finds indexes whose columns are a leading prefix of another index.

The longer index already serves the same queries, so the shorter one only adds write cost.

Recommendation: Drop the shorter index.

Never-used Indexes #

The check: Finds indexes with no scans since statistics were last reset.

An unused index costs storage and write time for no benefit. It may still be needed for a rarely-run query, or for a unique constraint.

Recommendation: Check Index Usage, then drop the index if it's truly unneeded.

High Dead Tuple Ratio #

The check: Finds tables with a large share of dead rows.

It's a sign of bloat and of autovacuum falling behind, which wastes space and slows queries.

Recommendation: Run Vacuum, and consider tuning autovacuum for the table.

Tables Not Vacuumed Recently #

The check: Finds tables with significant changes that haven't been vacuumed in over 7 days.

Dead rows accumulate and the planner's statistics grow stale.

Recommendation: Run Vacuum and Analyze, and check that autovacuum is running.

NOT VALID Constraints #

The check: Finds constraints that were never checked against existing rows.

Existing data may violate them, and the planner can't rely on them.

Recommendation: Run ALTER TABLE ... VALIDATE CONSTRAINT.

TIMESTAMP WITHOUT TIME ZONE #

The check: Finds timestamp columns with no time zone.

The stored value is ambiguous, which causes bugs when an application or its users span time zones.

Recommendation: Change the column to timestamptz, unless it truly holds local wall-clock time.

Fix maintenance issues with Vacuum and Analyze in Table Operations.