erd.sketch

Проверка SQL-схемы: что в ней не так

Ниже — не выдуманный список, а настоящий отчёт проверки для схемы слева. Те же находки вы увидите в редакторе на вкладке «Проверки», и часть из них там чинится кнопкой.

Что на входеschema.sql
CREATE TABLE user (
    id          BIGSERIAL PRIMARY KEY,
    email       VARCHAR(255) NOT NULL,
    balance     FLOAT,
    created_at  TIMESTAMP NOT NULL
);

CREATE TABLE orders (
    order_id    INTEGER NOT NULL,
    user_id     INTEGER REFERENCES user (id),
    total       FLOAT NOT NULL,
    placedAt    TIMESTAMP
);
Определилось как
PostgreSQL
ошибки 1замечания 8подсказки 2
Открыть редактор

Скрипт остаётся в браузере: и разбор, и генерация идут на вашей машине, на сервер ничего не уходит.

Что нашлось

  • Стороны связи разного типа

    orders.user_id

    Колонка и то, на что она ссылается, объявлены по-разному. Одни базы откажут сразу, другие будут молча приводить типы при каждом соединении.

  • Таблица без первичного ключа

    orders

    Строку такой таблицы нельзя надёжно адресовать: ни обновить одну из двух одинаковых, ни сослаться на неё. Репликация и ORM тоже рассчитывают на ключ.

  • Внешний ключ без индекса

    orders

    По этой колонке идут соединения и проверки при удалении родителя. Без индекса каждая из них — полный проход по таблице.

  • Внешний ключ допускает NULL

    orders.user_id

    Иногда так и задумано: связь необязательна. Но чаще NOT NULL просто забыли, и в таблице заводятся строки без родителя.

  • Имя — зарезервированное слово

    user

    Такое имя придётся в каждом запросе брать в кавычки. Переименовать дешевле, чем помнить об исключении.

  • Деньги в приблизительном типе

    user.balanceorders.total

    FLOAT и REAL хранят число приближённо: суммы перестают сходиться после первого же деления. Для денег нужен NUMERIC или DECIMAL.

  • TIMESTAMP без часового пояса

    user.created_atorders.placedAt

    В PostgreSQL такой столбец пояса не хранит и молча читается как местное время. При переезде сервера или переходе на летнее время значения разъезжаются — обычно имеется в виду timestamptz.

  • Разный стиль имён

    orders.placedAt

    В схеме соседствуют snake_case и camelCase. Перечислены имена в стиле меньшинства: привести их к общему проще, чем помнить исключения.

  • Не задано ON DELETE

    orders

    Что делать с потомками при удалении родителя, решает база — по умолчанию она удаление запретит. Если это не то, что нужно, лучше написать явно.