Руководство для проектирования хорошей схемы базы данных

Практически все Yii-приложения построены на базах данных. И хотя фреймворк Yii очень
гибок в плане взаимодействия с базой данных, некоторые решения призваны сделать разработку еще
проще и удобней.

Первый и наиболее важный момент заключается том, что Yii-приложения широко
используют шаблон ActiveRecord. Исходя из этого, все конструктивные соображения
направлены на оптимизацию такого использования, а не на человека, который будет
составлять сложные SQL-запросы. В самом деле, многие из проектных решений напрямую
конфликтуют с передовой практикой для создания дружественных SQL-схем.

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

Это особенно верно, в случае если вы просите о помощи на форумах или на канале #yii:
использование неподходящих имен, которые не отражают смысла, порождает много
вопросов и уточнений. Вы получите меньше справочной информации, чем могли бы.

Согласованность играет очень большую роль.

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

Называйте таблицы баз данных в единственном числе

SQL-таблицы содержат большое количество объектов, модель является лишь одним из
них: странно наблюдать такую картину, где $model = new Comments(). Такая конструкция
встречается снова при определении отношений и во многих других местах.

Назовите вашу таблицу comment вместо comments, invoice а не invoices и так далее, также
указывайте имена моделей классов (Comment, Invoice и т.д.).

Если вы не можете изменить схему базы данных, то измените хотя бы класс модели Yii. Обязательно
сделайте дополнительный комментарий в коде, чтобы напомнить другому пользователю про
это несоответствие.

Не предваряйте имена полей названием таблицы

Такая практика распространена в традиционном проектировании схемы SQL, но это
утомительно при работе с ActiveRecord. Ваша таблица category может иметь вид:

-- NO                              -- YES
create table category (            create table category(
    category_id    INTEGER ...,        id    INTEGER ...,
    category_name  VARCHAR ...,        name  VARCHAR ...,
    category_value INTEGER             value INTEGER
);                                 );
// YUCK                            // BETTER
$model->category_id                $model->id
$model->category_name              $model->name
$model->category_value             $model->value

Проделывая такой длинный путь, вы вручную создаете SQL-запросы, которые просты для
восприятия, но неудобны для использования в ActiveRecord.

Не включайте префикс таблицы в имя модели класса

Фреймворк Yii поддерживает понятие префикса таблицы, который используется в среде
виртуального хостинга, где все ваши приложения работают с единой базой данных.
Например, начиная названия таблиц блога с blog_, таблиц приложений — с time_ и т.д., вы
можете держать их в одной и той же базе данных, причем они не будут конфликтовать друг с
другом.

Во многих учебниках и примерах также часто встречается префикс tbl_.

Но классы не должны содержать эти префиксы, так как в этом нет необходимости. Ваш блог
и приложение — это две параллельные прямые, которые не пересекаются.

class TblComment extends CActiveRecord {       // NO
class Comment extends CActiveRecord {          // YES

Это очень отвлекает при просмотре кода.

Указывайте id в качестве идентификатора таблицы

Многие таблицы имеют независимый одиночный столбец с уникальным первичным ключом
(например, int NOT NULL AUTO_INCREMENT PRIMARY KEY). Многие вещи будут
работать плавнее, если называть столбец id (не commentid или postid).

Фреймворк Yii может обнаружить первичный ключ, обращаясь к схеме базы данных,
независимо от того, как вы его называете. Но другие части системы могут быть недоступны и
явно зависят от id ключа.

Пример: CArrayDataProvider обнаружил, что id является ключом, и хотя его можно
переопределить с помощью атрибута keyField, это создает дополнительные удобства, и вы
избегаете необходимость переопределения ключа.

Иногда это правило не применяется, например, когда таблица имеет несколько столбцов
с первичным ключом, или когда первичный ключ таблицы является внешним ключом к
другому идентификатору таблицы.

Избегайте семантически значимых первичных ключевых имен

Классическая ошибка при разработке — создание таблицы с первичным ключом, который
имеет актуальное значение. В этом примере в качестве первичного ключа использовано имя
пользователя:

-- don't do this!
CREATE TABLE user (
    name   VARCHAR(16) PRIMARY KEY,  -- bad idea
    email  VARCHAR...
    ...
)

Это создает две проблемы:

  1. Ссылки на это поле становятся гораздо менее эффективными, потому что оно содержит 16
    символов вместо четырехбайтового целого числа. Это может вызвать реальную проблему с
    производительностью в более крупном приложении с большим количеством ссылок.
  2. Пользователю будет сложнее изменить свое имя, если ограничения внешнего ключа
    включены в эту систему: поле таблицы и все ссылки должны быть изменены одновременно.
    Это дорого вам обойдется.

Гораздо лучше создать первичный ключ и сделать имя уникальным:

-- much better
CREATE TABLE user (
   id     INTEGER PRIMARY KEY AUTO_INCREMENT,
   name   VARCHAR(32) NOT NULL UNIQUE,
   email  ...
   ...
);

Таким образом, изменение имени пользователя приводит к обновлению только одной этой
записи.

Определите отношения внешнего ключа в схеме базы данных

Большинство баз данных позволяют устанавливать взаимоотношения между таблицами,
например: поле содержит идентификатор, указывающий на первичный ключ другой таблицы.
Эти внешние ключи и помогут обеспечить ссылочную целостность, не позволяя удалить
строку, если кто-то другой указывает на нее.

InnoDB в MySQL применяет ограничения внешнего ключа, и хотя MyISAM позволяет
определить их, он не будет проводить их в действие. Yii понимает, как следует
интерперетировать эти отношения из схемы, а инструменты Gii / Giix будет создавать
отношения автоматически.

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

Названия внешних ключевых полей должно заканчиваться на «id»

Если у вас есть поле, которое содержит идентификатор пользователя, вызывайте поле userid,
а не поле user. Это делается для того, чтобы для каждого внешнего ключа, который вы
подключили в таблицу, вы могли определить отношение.

В фреймворке Yii, класс переменных, поля базы данных, виртуальные атрибуты и отношения — все
разделяют единое пространство имен, так что конструкция $model->user не может быть и
внешним ключом в таблице, и отношением.

Вызывая внешний ключ userid, BELONGS_TO
относится к $model->user следующим образом:

class Post extends CActiveRecord {
 
   public function relations()
   {
       return array(
          'user' => array(self::BELONGS_TO, 'User', 'userid')
       );
   }

Примечание: некоторые предпочитают использовать Id или _id вместо идентификатора. Это
вопрос личных предпочтений, но будьте последовательны.

Называйте отношения с учетом их единственного или множественного характера

Продолжая тему последовательностей и создания удобочитаемого код, надо сказать, что
отношения должны отражать единство или множественность в своих названиях.

  • HAS_ONE — возвращает одиночную модель: singular
  • BELONGS_TO — возвращает одиночную модель: singular
  • HAS_MANY — возвращает массив моделей: plural
  • MANY_MANY — возвращает массив моделей: plural

Отметим, что отношения, возвращающие массив, могут иметь только одну модель, но по
факту массив будет иметь множественный характер.

Нужно делать так, чтоб вы могли определить — возвращает отношение массив или модель,
лишь взглянув на код:

Посмотрите на свой код и сделайте его легкочитаемым и простым в поддержке.