Исходный код сайта для проведения аудита доступен по ссылке

https://www.dropbox.com/sh/mf3xsb9cnn11d50/AABy0_i9a_ERDbX6Ahs6tJbta?dl=0

Аудит базы данных сайта сделанного в Мануфактура Софт, город Воронеж

Mysql


В целом структура плохо нормализована, типы данных выбраны неоптимально, пропущены ограничения по внешним ключам (целостность данных).

Индексы вообще нигде не используются (кроме стандартного PRIMARY, который создается вместе с таблицей).

Нестандартный default_collation=utf8mb4_0900_ai_ci (зачем?)

table added_education:

id_doctor - отсутствует FK связь (Constraint)

startyear - INT - неоптимальный тип данных (должен быть TINYINT)

stopyear - INT - неоптимальный тип данных (TINYINT)

active - INT - неоптимальный тип данных (TINYINT)

needaccept - неоптимальный тип данных (TINYINT)


table table admin:

id_user - INT (11) -отсутствует FK связь (Constraint)

table area:

id_region - отсутствует FK связь с таблицей regions (Constraint)

table articles:

id_doctor - отсутствует FK связь с таблицей doctors (Constraint)

datecreated - INT - правильно было бы DATETIME / TIMESTAMP

draft - INT - неоптимальный тип данных (TINYINT)

del - неоптимальный тип данных (TINYINT)

activated - неоптимальный тип данных (TINYINT)ъ

table calendar:

id_doctor - отсутствует FK связь с таблицей doctors (Constraint)

id_procedure - отсутствует FK связь с таблицей procedure (Constraint)

starttime - Для начала дня лучше было бы использовать CHAR (4 байта), вместо плохо читаемого INT в секундах (4 байта)

stoptime - аналогично

date - INT - должен быть TIMESTAMP / DATETIME

vacation - неоптимальный тип данных (TINYINT)

table captcha_counter:

В целом не было смысла писать эти данные в БД. Достаточно было бы записи в кеш.

ip_client - VARCHAR(45) - должно быть для ipv4 INT(4), для ipv6 BINARY(16)

registration_cnt - INT(5) - неоптимальный тип данных (TINYINT)

forgot_cnt - INT(5) - неоптимальный тип данных (TINYINT)

table catalog:

Ошибка в проектировании структуры!



В текущем виде вложенность категорий ограничена, нужно было строить граф (сейчас для каждого нового уровня вложенности придется создавать новую таблицу, если это характеристика станет динамической - придется все переделывать)

id_category - отсутствует FK связь с таблицей category (Constraint)

id_subcategory - отсутствует FK связь с таблицей category (Constraint)

id_doctor - отсутствует FK связь с таблицей doctors (Constraint)

id_doctor_update - неоптимальный тип данных (TIMESTAMP|DATETIME)

draft - неоптимальный тип данных (TINYINT)

del - неоптимальный тип данных (TINYINT)

favorite - неоптимальный тип данных (TINYINT)

datecreated - INT - правильно было бы DATETIME / TIMESTAMP

dateupdated - INT - правильно было бы DATETIME / TIMESTAMP

activated - INT - неоптимальный тип данных (TINYINT)

needupdate - INT - неоптимальный тип данных (TINYINT)

change_dateupdate - INT - правильно было бы DATETIME / TIMESTAMP

change_id_doctor_update - отсутствует FK связь с таблицей doctors (Constraint)

change_id_category - отсутствует FK связь с таблицей category (Constraint)

change_id_subcategory - отсутствует FK связь с таблицей subcategory (Constraint)

table catalog_info:

id_region - отсутствует FK связь с таблицей regions (Constraint)

del - INT - неоптимальный тип данных (TINYINT)

table catalog_info:

type - ENUM('PATIENT', 'DISEASE', 'DRUGS') - нужно было выносить типы в отдельную категорию, а тут привязывать по FK

del - INT - неоптимальный тип данных (TINYINT)

table clinic:

id_user - отсутствует FK связь с таблицей users (Constraint)

id_organization - отсутствует FK связь с таблицей organizations (Constraint)

id_country - отсутствует FK связь с таблицей countries (Constraint)

id_region - отсутствует FK связь с таблицей regions (Constraint)

id_area - отсутствует FK связь с таблицей areas (Constraint)

id_station - отсутствует FK связь с таблицей stations (Constraint)

post_code - INT (6) - должно быть MEDIUM INT (6) ZEROFILL

part_house - VARCHAR(5) - должно быть CHAR(5)

datereg - должно быть DATETIME / TIMESTAMP

activated - неоптимальный тип данных (TINYINT)

del- неоптимальный тип данных (TINYINT)

stoprecord - INT(2) - неоптимальный тип данных (TINYINT)

excludesearch - INT (1) - неоптимальный тип данных (TINYINT)

table clinicinfo_change:

id_clinic - отсутствует FK связь с таблицей clinics (Constraint)

  • аналогичные связи и замечания, описанные выше

house - VARCHAR - должно быть CHAR

part_house - VARCHAR - должно быть CHAR

needaccept - неоптимальный тип данных (TINYINT)

table coming_soon:

email - VARCHAR(60) - нужно VARCHAR(320). https://tools.ietf.org/html/rfc5321.html

table comments:

  • аналогичные связи и замечания, описанные выше

table doc_contracts:

  • аналогичные связи и замечания, описанные выше

is_sign - INT(1) - неоптимальный тип данных (TINYINT)

table doc_report2grid:

  • аналогичные связи и замечания, описанные выше

id_doc_report - отсутствует FK связь с таблицей doc_reports (Constraint)

id_grid - отсутствует FK связь с таблицей grid (Constraint)

table doc_reports:

  • аналогичные связи и замечания, описанные выше

table doctor:

  • аналогичные связи и замечания, описанные выше

subspecialty - вероятно нужно было для этого завести отдельную структуру и организовать связь (ONE-TO-MANY|MANY-TO-MANY). В текущем исполнении по этому полю даже поиск нормально сделать невозможно

startprofdate - INT(1) - должно быть DATETIME / TIMESTAMP

table users:

Плохо спроектирована ролевая модель + ненормализована. В текущем исполнении пользователь не сможет иметь несколько ролей (если вдруг будет необходимо доработать систему таким образом)