В базе данных, когда следует хранить производные данные?

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

Например, скажите, что у вас есть пользователи, которые получают Upvotes для своих вопросов. Вы показываете репутацию пользователя в своем профиле. Когда пользователь получает поддержку, если вы увеличиваете свою репутацию или вы должны рассчитывать его при получении своего профиля:

SELECT User.id, COUNT(*) AS reputation FROM User
LEFT JOIN Question
  ON Question.User_id = User.id
LEFT JOIN Upvote
  ON Upvote.Question_id = Question.id
GROUP BY User.id

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

Чтобы продолжить наш пример, предположим, что Upvote имеет вес, который зависит от того, сколько Upvotes (а не сколько репутации) имеет Пользователь, который его создал. Запрос на получение своей репутации внезапно взрывается:

SELECT
  User.id AS User_id,
  SUM(UpvoteWeight.weight) AS reputation
FROM User
LEFT JOIN Question
  ON User.id = Question.User_id
LEFT JOIN (
  SELECT
    Upvote.Question_id,
    COUNT(Upvote2.id)+1 AS weight
  FROM Upvote
  LEFT JOIN User
    ON Upvote.User_id = User.id
  LEFT JOIN Question
    ON User.id = Question.User_id
  LEFT JOIN Upvote AS Upvote2
    ON
      Question.id = Upvote2.Question_id
      AND Upvote2.date < Upvote.date
  GROUP BY Upvote.id
) AS UpvoteWeight ON Question.id = UpvoteWeight.Question_id
GROUP BY User.id

Это далеко не пропорционально сложности инкрементного решения. Когда нормализация будет стоить того, и когда преимущества нормализации теряют пользу от денормализации (в данном случае сложность запроса и/или производительность)?

Ответ 1

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

Здесь есть два вопроса: (1) Будет ли это изменение улучшать производительность и (2) Будет ли улучшение производительности стоить усилий?


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

Преимущества нормализации в основном двукратные:

  • Простая целостность данных

  • Нет проблем с повторным вычислением (например, если базовые данные изменяются, производный столбец необходимо пересчитать).

Если вы охватите целостность данных с помощью надежного решения (например, триггер, данные Sstored-proc-only с отмененными первыми изменениями таблицы и т.д.), тогда это станет прямым вычислением того, стоит ли проверять стоимость проверки является ли изменение исходных данных оправданием перепроизводства полученных данных и пересчет полученных данных каждый раз. (ПРИМЕЧАНИЕ. Еще один подход к сохранению целостности данных - заставить перерасчет производных данных по расписанию, когда эти данные могут позволить себе неточно с некоторым временным допуском. StackExchange использует этот подход с некоторыми его номерами).

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

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


Теперь мы решаем гораздо более важный вопрос: Будет ли улучшение производительности стоить усилий?

Обратите внимание, что, как и при ВСЕХ оптимизации, самый большой вопрос: "Оптимизация даже стоит того?", и как таковая обсуждается двумя основными соображениями:

  • Измерение точной разницы в производительности и, как правило, профилирование.

  • Контекст этой конкретной оптимизации в общей картине вашей системы.

например. если разница в запросе performace - , которая, как всегда, при оптимизации должна быть сначала измерена - составляет 2% между кэшированными производными данными и вычисленными, дополнительная сложность системы при внедрении столбца кэша репутации может не стоить в первую очередь. Но то, что порождает заботу, а не забота, заключается в том, что предельное улучшение зависит от большой картины вашего приложения. Если вы можете предпринять шаги для повышения производительности запросов на 10% в другом месте, сосредоточьтесь на этом против 2%. Если вы Google, и дополнительные 2% производительности запросов несут расходы в 2 миллиарда долларов за дополнительное оборудование, чтобы их нести, их все равно нужно оптимизировать.

Ответ 2

На самом деле нет четкого ответа, потому что это зависит от множества факторов, таких как объем сайта и как часто вы показываете репутацию (то есть только на странице своего профиля или рядом с КАЖДОМ экземпляром своего имени пользователя), Единственный реальный ответ - "когда он становится слишком медленным"; другими словами, вам, вероятно, потребуется протестировать оба сценария и получить некоторые реальные показатели производительности.

Лично я денормализую в этой конкретной ситуации и имею либо триггер insert в таблице upvote, либо периодический запрос обновления, который обновляет столбцы denromalized репутации. Неужели это будет конец света, кто-нибудь из представителей сказал "204" вместо "205", пока страница не обновится?

Ответ 3

Я просто хотел поднять другой подход к проблеме целостности данных, который DVK так хорошо рассмотрел в ответе выше. Подумайте, нужны ли другим системам для доступа/вычисления полученных данных - даже что-то простое, как система отчетности. Если другим системам необходимо использовать производное значение или обновить значение upvote, тогда у вас могут возникнуть дополнительные соображения о том, как повторно использовать код вычисления или как обеспечить постоянное обновление производного значения независимо от того, какая система изменяет верхнюю часть.