Система голосования: я должен использовать триггер SQL или больше кода? - PullRequest
2 голосов
/ 20 января 2011

Я строю систему голосования, в которой каждый голос фиксируется в таблице голосов с UserID и DateTime голосов вместе с int либо 1 или -1 .

Я также держу промежуточный итог TotalVotes в таблице, содержащей элемент, за который фактически проголосовал пользователь.Таким образом, я не постоянно выполняю запрос к SUM таблице голосования.

Мой вопрос является своего рода вопросом "за / против", когда дело касается обновления поля TotalVotes.Что касается управляемости кода, добавление дополнительного метода обновления в приложение позволяет легко устранять неполадки и обнаруживать любые потенциальные проблемы.Но если это приложение значительно расширится в своей пользовательской базе, это может вызвать много дополнительных вызовов SQL из приложения в БД.Использование триггера сохраняет его «все в семействе sql», так сказать, и должно добавить небольшое повышение производительности, а также не допустить обыденной активности за пределы кодовой базы.назвал этот конкретный вопрос, но так как я еще не построил его, я мог бы также попытаться найти лучший подход прямо из ворот.

Лично я склоняюсь к курку.Пожалуйста, дайте мне ваши мысли / рассуждения.

Ответы [ 5 ]

3 голосов
/ 20 января 2011

Другой вариант - создать представление таблицы голосов, объединяющее голоса в виде TotalVotes.Затем индексируйте представление.

Волшебство оптимизатора SQL Server (я думаю, что только для корпоративной версии) заключается в том, что, когда он видит запросы суммы (voiceColumn), он выбирает это значение из индекса для представления того жеданные, что удивительно, если учесть, что вы не ссылаетесь на представление непосредственно в своем запросе!

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

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

Извлечение Повышение производительности с помощью индексированных представлений

Существуют некоторые конкретные критерии, которые должны быть соблюдены для работы индексированных представлений.Вот пример, основанный на предположении вашей модели данных:

create database indexdemo
go
create table votes(id int identity primary key, ItemToVoteOn int, vote int not null)
go

CREATE VIEW dbo.VoteCount WITH SCHEMABINDING AS
select ItemToVoteOn, SUM(vote) as TotalVotes, COUNT_BIG(*) as CountOfVotes from dbo.votes group by ItemToVoteOn
go
CREATE UNIQUE CLUSTERED INDEX VoteCount_IndexedView ON dbo.VoteCount(itemtovoteon)
go
insert into votes values(1,1)
insert into votes values(1,1)
insert into votes values(2,1)
insert into votes values(2,1)
insert into votes values(2,1)
go

select ItemToVoteOn, SUM(vote) as TotalVotes from dbo.votes group by ItemToVoteOn

И этот запрос (который не ссылается на представление или, по расширению, его индекс) приводит к этому плану выполнения.Обратите внимание, что индекс используется.Конечно, отбросьте индекс (и увеличьте производительность вставки)

alt text

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

2 голосов
/ 20 января 2011

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

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

2 голосов
/ 20 января 2011

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

Если вам не нужно денормализовать данные, вам не нужно писать триггер.

1 голос
/ 21 января 2011

Я делал триггерный метод годами и всегда был счастливее. Так что, как говорится, «давай, вода в порядке». Однако обычно я делаю это, когда задействовано много таблиц, а не одна.

Плюсы / минусы хорошо известны. Материализация значения - это решение "заплати мне сейчас", вы платите немного больше за вставку, чтобы получить более быстрое чтение. Это путь, если и только если вы хотите чтение в 5 миллисекунд вместо 500 миллисекунд.

PRO: TotalVotes всегда будет доступна сразу после одного чтения.

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

CON: за каждую ВСТАВКУ вы также платите дополнительным ОБНОВЛЕНИЕМ. Требуется намного больше вставок в секунду, чем думает большинство людей, прежде чем вы заметите это.

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

CON: для обеспечения полной корректности не должно быть возможности выдавать UPDATE из консоли или кода для изменения TotalVotes. Это значит, что это сложнее. Триггер должен работать как специальный суперпользователь, который обычно не используется. Второй триггер в родительской таблице срабатывает при UPDATE и предотвращает изменения в TotalVotes, если только пользователь, производящий обновление, не является этим специальным суперпользователем.

Надеюсь, этого достаточно, чтобы принять решение.

1 голос
/ 20 января 2011

Моим первым инстинктом было бы написать UDF для выполнения операции SUM и сделать TotalVotes вычисляемым столбцом на основе этого UDF.

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