Создание переменной в базе данных для хранения глобальной статистики - PullRequest
5 голосов
/ 03 июня 2011

Давайте представим, что у меня есть социальная сеть. Я всегда показываю пользователю, сколько пользователей зарегистрировано и активировали свой профиль. Таким образом, каждый раз, когда один пользователь входит в систему, он попадает в БД и создает:

select count(*) from users where status = 'activated'

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

Как я могу это сделать? Это действительно лучшее решение того, что у меня есть?

Ответы [ 5 ]

2 голосов
/ 03 июня 2011

Вы можете использовать индексированное представление, которое SQL Server будет поддерживать автоматически:

create table dbo.users (
    ID int not null,
    Activated bit not null
)
go
create view dbo.user_status_stats (Activated,user_count)
with schemabinding
as
    select Activated,COUNT_BIG(*) from dbo.users group by Activated
go
create unique clustered index IX_user_status_stats on dbo.user_status_stats (Activated)
go

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

SELECT user_count from user_status_stats with (NOEXPAND) where Activated = 1

и ему не придется запрашивать основную таблицу. Вам нужно использовать подсказку WITH (NOEXPAND) в следующих выпусках (Enterprise / Developer).


Хотя, как предложил @Jim, выполнение COUNT (*) для индекса, когда столбцы столбцов индекса могут удовлетворять критериям запроса с использованием сравнений на равенство, также должно быть довольно быстрым.

1 голос
/ 03 июня 2011

Как вы уже догадались, рассчитывать это значение не стоит каждый раз, когда кто-то посещает сайт.

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

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

В качестве альтернативы # 2, вы можете использовать что-то вроде MemCache для хранения вычисленного значения в течение некоторого периода времени, а затем, когда срок действия кэша истечет, пересчитать его снова.

0 голосов
/ 03 июня 2011

Вы также можете использовать Глобальную временную таблицу . Вы всегда получите быстрый поиск. Четное если вы устанавливаете 30 секунд пинг. Пример триггерной ссылки1 , Пример триггерной ссылки2 будет поддерживать такие действия в этой таблице.

0 голосов
/ 03 июня 2011

С точки зрения чисто SQL Server, нет, вы не найдете лучшего способа сделать это.Если, возможно, ваша социальная сеть не имеет размер Facebook.Денормализация вашего дизайна данных (например, ведение счета в отдельной таблице) приведет к тому, что возможные источники данных будут синхронизированы.Он не должен выходить из синхронизации, если он правильно закодирован, но он может ...

Просто убедитесь, что у вас есть индекс состояния.В этот момент SQL не будет сканировать таблицу для подсчета, но вместо этого будет сканировать index .Индекс будет намного меньше (то есть больше данных поместится на странице диска).Если бы вы преобразовали свой статус в int, smallint или tinyint, вы бы получили еще больше индексных листов на странице диска и, следовательно, гораздо меньше операций ввода-вывода.Чтобы получить описание («активировано» и т. Д.), Используйте справочную таблицу.Таблица ссылок была бы настолько мала, что SQL просто сохранял бы все это в ОЗУ после первого доступа.

Теперь, если вы все еще думаете, что это слишком много (и не должно быть), вы можете прийтис гибридным методом.Вы можете сохранить ваш счетчик в отдельной таблице (который SQL будет хранить в ОЗУ, если это всего лишь одна запись) или, предполагая, что ваш сайт находится в asp.net, вы можете создать переменную Application для отслеживания количества.Вы можете увеличить его в Session_Start и уменьшить в Session_End.Но вам придется придумать способ сделать поток увеличения и уменьшения безопасным, чтобы две сессии не пытались обновить значение одновременно.

0 голосов
/ 03 июня 2011

Есть несколько вариантов, которые вы можете рассмотреть:

1) как вы говорите, поддерживайте глобальный счет каждый раз, когда активируется профиль, чтобы каждый раз сохранять попадание в таблицу пользователей.Вы можете просто сохранить это количество в таблице «Статистика», а затем запросить это значение оттуда.

2) не показывать фактическое «живое» количество, показывать счет, который «довольно актуален»- например, кешировать счетчик в вашем приложении и периодически его значение истекает, поэтому вы будете запрашивать счетчик реже.Или, если вы сохраняете счет в таблице «Статистика», как указано выше, у вас может быть запланированное задание, которое обновляет счет каждый час, а не каждый раз, когда активируется профиль.

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

...