Хранение рассчитанных значений в базе данных - плохая идея? - PullRequest
0 голосов
/ 07 мая 2018

Допустим, я разрабатываю проект магазина. Итак, мне нужно создать таблицу с именем «Продукт» в моей базе данных. Скажем, я также хочу, чтобы пользователи могли «любить» мои продукты. Таким образом, я должен создать еще одну таблицу с именем «ProductLike» для хранения идентификаторов пользователей, а также идентификаторов продуктов, которые им нравятся.

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

Мой вопрос: Итак, я знаю, что стандартный подход - не хранить «Расчетные значения» в базе данных. Но как насчет таких случаев? (Случаи, которые занимают много времени для расчета стоимости). Например, в приведенном выше примере, не лучше ли иметь столбец с именем «NumberOfLikes» в таблице «Product» для хранения рассчитанного количества лайков продукта?

Ответы [ 4 ]

0 голосов
/ 07 мая 2018

Обновление

не лучше ли иметь столбец с именем NumberOfLikes в таблице «Продукт» для хранения рассчитанного количества лайков продукта?

ИМХО, прямой ответ на этот вопрос: «Нет, если у вас нет реальной проблемы с производительностью из-за подсчета лайков».

Если у вас есть проблема с производительностью, и вы определили ее источник как количество лайков, то вы можете рассмотреть возможность добавления столбца LikesCount в таблицу products. Если вы добавите такой столбец, обратите внимание, что вам придется обновлять его при каждом изменении таблицы ProductLike - удалять, обновлять и вставлять.
Это означает, что вам нужно написать триггер для этой таблицы, чтобы обработать все эти случаи, но это не должно быть слишком сложно, так как вы можете делать все за один триггер - что-то вроде этого:

create trigger ProductLikeChaneged on ProductLike 
for insert, update, delete
as

    update p
    set LikesCount = (select count(*) from ProductLike as pl where pl.productId = p.Id)
    from product as p
    where exists
    (
        select 1 from inserted as i where p.id = i.productId
    )
    or exists
    (
        select 1 from deleted as d where p.id = d.productId
    )

Оригинальная версия
Исходя из вашего описания, «вычисление» количества лайков для продукта - это просто количество строк в таблице ProductLike, где id продукта - это идентификатор продукта, который вы в данный момент отображаете для пользователя.
Это можно сделать очень быстро, особенно если кластеризованный индекс таблицы ProductLike равен ProductId, а затем UserId, что позволяет SQL Server использовать поиск кластеризованного индекса, а не сканирование таблицы.

По сути, ваша таблица ProductLike должна выглядеть следующим образом:

 Create table ProductLike
 (
     ProductId int,
     UserId int,
     Constraint PK_ProductLike PRIMARY KEY (ProductId, UserId)
 )

Обратите внимание, что по умолчанию SQL Server будет использовать первичный ключ в качестве кластеризованного индекса таблицы.

Тогда ваш оператор выбора для страницы продукта может выглядеть примерно так:

select Name, Description, -- Other product related details
       (select count(*) 
        from productLike as pl 
        where pl.ProductId = p.Id) as likeCount
from product as p
0 голосов
/ 07 мая 2018

Под «вычисленным» значением я подозреваю, что вы имеете в виду накопление количества запросов.

Самый простой подход с точки зрения проектирования и обслуживания базы данных - хранить каждый запрос в виде строки в таблице и суммировать при необходимости. Это имеет некоторые приятные особенности:

  • Пользователь может легко «отменить запрос» или «в отличие».
  • Вставки находятся (как правило) в «конце» таблицы, минимизируя фрагментацию и ускоряя вставки. Примечание. Это может привести к конфликту за последнюю страницу, если несколько потоков пишут одновременно.
  • Счет может быть гибким, например, ограниченным конкретным диапазоном дат или типом пользователя.
  • Данные доступны для детализации. То есть для данного подсчета вы точно знаете, что его произвело.

Суммирование часто очень разумно, если у вас есть правильные индексы и разделы в данных.

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

0 голосов
/ 07 мая 2018
  • Номер понравившегося пользователю товара может быть получен из таблицы UserProductLike, где ID пользователя - это идентификатор вашего пользователя.

enter image description here

0 голосов
/ 07 мая 2018

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

Отказ от ответственности: Ваш вопрос основывается на мнении, я думаю, он будет закрыт через некоторое время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...