Требования к базам данных

Важно

Не используйте в именах таблиц и полей зарезервированные слова MySQL.

Имена таблиц

  • Таблицы, хранящие основные данные сущностей, именуются названием сущности в множественном числе. Для примера возьмём таблицу products, которая содержит основную информацию о товарах магазина.
  • Таблицы, хранящие дополнительные данные сущностей или дочерние сущности, именуются по шаблону сущность_суффикс. Добавляемый суффикс именуется во множественном числе. Для примера, таблица, содержащая цены товаров, называется product_prices.
  • Для понимания правил именования таблиц в более сложных случаях зависимостей таблиц друг от друга подойдёт такой пример:
    • products — хранит основную информацию о товарах;
    • product_features — хранит доступные для присвоения характеристики товаров;
    • product_feature_variants — хранит доступные для присвоения варианты характеристик товаров;
    • product_feature_variant_descriptions — хранит мультиязычные поля вариантов характеристик товаров для каждого языка.

Важно

C каждым следующем уровнем зависимостей таблиц во множественном числе именуется только последний суффикс.

Префикс таблиц

При установке системы администратор задаёт префикс, который будет использован при создании всех таблиц. Префикс по-умолчанию — cscart_. В SQL-запросах, выполняемых из CS-Cart с помощью встроенных функций для работы с БД, выбранный префикс будет заменять собой плейсхолдер ?:. Таким образом, если вы упоминаете в SQL-запросе название таблицы, вы обязательно должны добавлять перед названием плейсхолдер ?:.

Короткий пример:

$products = db_get_array(
    'SELECT * FROM ?:products LEFT JOIN ?:product_popularity USING(product_id)'
);

Названия полей первичных ключей

Исторически так сложилось, что поля и первичных, и внешних ключей именуются с префиксом названия сущности. Это означает, что, например, в таблице products поле с уникальным первичным ключом будет называться product_id. Cоветуем придерживаться этого правила при разработке модификаций CS-Cart. Даже если вы не согласны с таким правилом именования, это позволит всей кодовой базе выглядеть однотипно и однородно.

Интернационализация

Сущности, хранящиеся в БД, могут иметь поля, содержимое которых должно отличаться для разных языков. Например, у товаров как минимум название и описание может быть мультиязычным. Для хранения таких полей в CS-Cart используется следующий подход:

  • Создаётся отдельная таблица с названием сущность_descriptions, в нашем примере это product_descriptions.

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

  • Кроме того, таблица должна содержать поле, которое будет содержать код языка, для которого добавлена запись в таблицу. Обычно это поле называется lang_code и имеет тип CHAR(2).

  • Затем в таблицу добавляются поля, которые должны быть мультиязычными.

    В нашем примере это помимо прочих product — название товара, и full_description — подробное описание товара.

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

  • При создании нового товара учитывать, какой язык выбран в для редактирования в панели администратора (константа DESCR_SL) — сохранять данные в таблицу product_descriptions со значением поля lang_code равным значению константы DESCR_SL.

  • При выборке данных для отображения в клиентской части, нужно присоединять таблицу с мультиязычными данными по условию “lang_code равен выбранному пользователем языку в клиентской части (значение константы CART_LANGUAGE)”.

    Пример подобного SQL-запроса:

    SELECT products.*, product_descriptions.* FROM products
    INNER JOIN product_descriptions
        ON product_descriptions.product_id = products.product_id
        AND product_descriptions.lang_code = 'en'
    

Тип таблиц

Исторически сложилось, что для всех таблиц CS-Cart используется MyISAM. Однако ничто не мешает вам при необходимости сменить тип таблиц на InnoDB — система будет работать корректно в этом случае.

InnoDB имеет ряд преимуществ относительно MyISAM:

  • внешние ограничения;
  • продвинутое использование индексов в последних версиях MySQL;
  • транзакции;

Примечание

Из-за особенностей внутреннего устройства запросы на запись и удаление данных в InnoDB могут занимать больше времени, чем в MyISAM.

Важно: внешние ограничения, которые вы можете добавить к таблицам в случае миграции на InnoDB, могут некорректно работать с порядком выполнения запросов изменения/удаления данных в CS-Cart. Например, при удалении категории сначала удаляется запись в таблице categories, а затем все дочерние товары и подкатегории. Это может вызвать проблемы с каскадными ограничениями ссылочной целостности вида ON UPDATE CASCADE/ON DELETE CASCADE — CS-Cart на уровне PHP-кода реализует обновление и удаление связанных сущностей.

Важно

Настоятельно рекомендуем реализовывать логику каскадного обновления/удаления данных именно в PHP-коде.

Логика в СУБД

Мы не рекомендуем использовать логику в БД (триггеры, хранимые процедуры и т. п.) при разработке аддонов, потому что это может вызвать проблемы с совместимостью вашего аддона и настройками MySQL на серверах клиентов - требуемые привилегии для создания триггеров и хранимых процедур могут отсутствовать. Кроме того, как и в случае с внешними ограничениями, добавляемая вами логика в БД может дублировать или конфликтовать с логикой, реализованной в PHP-коде системы.

Типы полей

Целочисленные поля

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

Пример: Вы делаете флаговое поле (1,0) и решили использовать тип INT. Конечно тут нелогично использовать всю размерность поля INT — оно занимает 4 байта. Нужно использовать TINYINT (3) размером в 1 байт для экономии дискового пространтсва, выделяемого под данные. Так выборки будут шустрее.

Также не нужно забывать про флаг UNSIGNED для полей, которые являются положительными. Это в 2 раза увеличит диапазон значений.

Дополнительный числовой атрибут у типа поля вляет на отображение поэтому желательно его пропускать — MySQL сам выберет подходящую размерность. Например для TINYINT будет выбрано 3 а для SMALLINT — 5.

Описание INT полей есть на этой странице.

Сводная таблица диапазонов для INT полей, первым идёт диапазон для флага UNSIGNED:

TINYINT SMALLINT MEDIUMINT INT BIGINT
-128
127
-32768
32767
-8388608
8388607
-2147483648
2147483647
-9223372036854775808
9223372036854775807
0 255 0 65535 0 16777215 0 4294967295 0 18446744073709551615

Строковые поля

Данная секция касается полей которые используются как уникальные идентификаторы. В новой версии они также оптимизированы. К примеру, поле email во всех таблицах приведено к типу VARCHAR (64).

Общая рекомендация — выбирать размер поля более маленьким, чтобы избежать избычности. К примеру, нелогично ставить такому полю тип VARCHAR (255) — если есть реально ключи такой длины, впору подумывать об их сокращении.

Другие поля

Для ценовых полей используется тип DECIMAL (9,2).

Strict mode

На некоторых серверах (и последних версиях MySQL) strict-режим включен по умолчанию. Для того, чтобы таблицы соответствовали этому режиму, необходимо соблюдать несколько правил:

  • Для полей с типом TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT, BLOB, MEDIUMBLOB запрещено использовать аттрибут DEFAULT.
  • Запрещено использовать аттрибут NOT NULL без доп. аттрибута DEFAULT.

Плохо:

`some_field` text NOT NULL DEFAULT ''

Хорошо:

`some_field` text

Плохо:

`some_field` char(1) NOT NULL

Хорошо:

`some_field` char(1) NOT NULL DEFAULT 'A'