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

Всем доброго времени суток! <br/> Прошу поделиться опытом и советами по правильной организации структуры базы данных для сети магазинов. <br/> <br/> У нас есть магазины в различных городах: Москва, Санкт-Петербург, Новосибирск и Екатеринбург, с планами на расширение в другие города. <br/> <br/> Следующие моменты важны для понимания ситуации: <br/> 1. У каждого города своя (полностью отдельная) база 1С с информацией о товарах. <br/> 2. Структура баз 1С идентична, что позволит использовать единый функционал для импорта товаров. <br/> 3. В каждой базе присутствуют свои склады с различными остатками товаров. <br/> 4. Товары в основном совпадают, но есть уникальные позиции для каждого города (примерно 70% общих и 30% уникальных товаров). <br/> 5. У каждого товара три типа цен: для всех, для партнеров и для оптовиков. <br/> 6. В базе предполагается наличие от 10 000 до 15 000 товаров. <br/> 7. Сайт будет обслуживать несколько городов, и в зависимости от выбора города должны отображаться соответствующие товары. Если филиал в городе отсутствует, будут показаны товары из базы по умолчанию (Москва). <br/> <br/> Я планирую создать следующие таблицы в БД: <br/> <code>product</code> - название, описание, категория, фотографии; <br/> <code>product_price</code> - цена, тип цены (числовое обозначение, как указано в пункте 5); <br/> <code>warehouse</code> - название склада (для получения id); <br/> <code>product_quantity</code> - id склада, количество остатков. <br/> <br/> Итак, у меня вопрос: как правильно организовать структуру базы данных для учета нескольких городов? Я рассматриваю два варианта, и мне нужна помощь в выборе оптимального. <br/> <br/> Вариант 1. <br/> Создать таблицы, указанные выше, и добавить в каждую из них...
  • 2 января 2025 г. 19:54
Ответы на вопрос 2
Для организации структуры базы данных интернет-магазина, который предлагает товары из разных источников и учитывает специфику каждого города, можно рассмотреть несколько важных аспектов. Исходя из ваших требований, можно предложить следующий подход к проектированию базы данных.

### Основные таблицы и их связи

1. **Таблица `city`**: содержит информацию о городах.
   ```sql
   CREATE TABLE city (
       id SERIAL PRIMARY KEY,
       name VARCHAR(50) NOT NULL,
       default_warehouse_id INT, -- id склада по умолчанию для этого города
       UNIQUE(name)
   );
   ```

2. **Таблица `product`**: совмещает общую информацию о товарах.
   ```sql
   CREATE TABLE product (
       id SERIAL PRIMARY KEY,
       name VARCHAR(255) NOT NULL,
       description TEXT,
       category VARCHAR(255),
       images JSONB
   );
   ```

3. **Таблица `product_price`**: хранит цену товара в зависимости от типа:
   ```sql
   CREATE TABLE product_price (
       id SERIAL PRIMARY KEY,
       product_id INT REFERENCES product(id),
       city_id INT REFERENCES city(id),
       price NUMERIC(10, 2),
       price_type VARCHAR(20) CHECK (price_type IN ('retail', 'partner', 'wholesale'))
   );
   ```

4. **Таблица `warehouse`**: хранит информацию о складах.
   ```sql
   CREATE TABLE warehouse (
       id SERIAL PRIMARY KEY,
       name VARCHAR(255) NOT NULL,
       city_id INT REFERENCES city(id)
   );
   ```

5. **Таблица `product_quantity`**: отслеживает остатки товара на складах.
   ```sql
   CREATE TABLE product_quantity (
       id SERIAL PRIMARY KEY,
       product_id INT REFERENCES product(id),
       warehouse_id INT REFERENCES warehouse(id),
       quantity INT NOT NULL
   );
   ```

### Логика работы

1. **Тип товара и цены**: Каждое значение цены будет связываться с определённым городом, что позволит вам иметь разные цены в зависимости от города. С полем `city_id` в таблице `product_price` вы сможете отделить цены для разных городов.

2. **Остатки товаров**: С помощью таблицы `product_quantity` вы сможете иметь количественные остатки товаров на разных складах, ассоциированных с конкретными городами. Основное различие здесь — это склад, на котором хранится товар.

3. **Отображение товара на сайте**: При запросе товаров на сайт можно будет легко фильтровать по `city_id`, чтобы отобразить товары, актуальные для выбранного города; в случае отсутствия товаров в базе для данного города, можно использовать товары из базы по умолчанию (например, по Москве).

### Дополнительные рекомендации

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

- Храните фотографии товаров во внешнем хранилище (например, AWS S3) и сохраняйте ссылки в базе данных, чтобы уменьшить нагрузку на базу данных.

- Обеспечьте обработку версии базы данных для контроля изменений, функций и схемы.

Такой подход предоставит вам четкую и гибкую архитектуру для управления товарами и их наличием в зависимости от городов, в то же время учитывая более глубинные детали, такие как цены и остатки.
И вот здесь основные сомнения: сделать выборку из 15 000 строк быстрее, чем из 60 000 (и будет больше) с WHERE city='spb'. На старте хотелось бы сделать правильно, чтобы при последующем развитии не упереться и переписываться все заново.
Современные бд вообще с такими объемами смешными справляются достаточно легко, скорость может проседать в районе миллиона записей, и там уже надо думать как это хитро индексировать/шардировать или тюнить железо/софт (естественно и тестовая машина должна быть какой-то адекватной конфигурации). По этому такая экономия на спичках по итогу выйдет боком. Собственно вам ничего особенно не стоит создать фейкером 15/60К записей со связями и прогнать эксплэйн на запрос, посмотреть чего в индексах не хватает, как быстро идет выборка... И WHERE city='spb' скорее всего вам аукнется, нужно связывать со справочной таблицей городов и соединять по айди-сити_айди, или через пивот, если у товара может быть больше одного города.
Похожие вопросы