Эффективный способ моделирования агрегированных данных отношения многие-к-одному (например, подсчет голосов по вопросу о переполнении стека) - PullRequest
1 голос
/ 29 мая 2009

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

Я продолжу с примером stackoverflow

Question
  id
  title
Votes
  id
  user
  question

Вопрос имеет много голосов

Однако для многих запросов нас интересует только общее количество голосов (например, для отображения рядом с вопросом).

Хорошая теория реляционных БД создала бы две сущности (Q и V) как отдельные отношения, требующие объединения, а затем совокупного вызова суммы или количества.

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

Могут использоваться другие методы, включающие кэширование и т. Д. Но мне просто интересно, с точки зрения производительности, какое решение лучше? Скажем, на сайте больше трафика и он получает значительно больше голосов, чем вопросов.

Открыт также для нереляционных моделей.

Ответы [ 3 ]

1 голос
/ 29 мая 2009

Я использовал индексированные представления из sql 2005 повсеместно для такого рода вещей на сайте социальной сети. Наша загрузка определенно была высокой для чтения / записи, поэтому она хорошо сработала.

1 голос
/ 29 мая 2009

Маловероятно, что в этом случае объединение будет слишком медленным, особенно если у вас есть индекс (вопрос) в таблице голосов.

Если он ДЕЙСТВИТЕЛЬНО слишком медленный, вы можете кэшировать счетчик голосов в таблице вопросов:

 id - title - votecount

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

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

 UPDATE q
 SET votecount = count(v.question)
 FROM questions q
 LEFT JOIN votes v on v.question = q.id

Совокупный счет (v.question) возвращает 0, если не было найдено ни одного вопроса, в отличие от count (*), который возвращает 1.

Если блокировки являются проблемой, рассмотрите возможность использования «with (nolock)» или «установить уровень изоляции транзакции для чтения без передачи» для обхода блокировок (опять же, на основании целостности данных, имеющей низкий приоритет.)

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

ALTER DATABASE YourDb SET READ_COMMITTED_SNAPSHOT ON;

Доступно для SQL Server 2005 и выше. Это то, как Oracle работает по умолчанию, и это то, что использует сам stackoverflow. Об этом даже есть кодовая запись в блоге ужасов .

0 голосов
/ 29 мая 2009

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

...