Рекомендации по обновлению нескольких флажков на веб-форме в базе данных - PullRequest
0 голосов
/ 20 декабря 2009

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

QuestionAnswers
(
  UserID int,
  QuestionID int,
  AnswerID int
)

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

В моем текущем проекте производительность и масштабируемость очень важны, поэтому мне интересно, как лучше это сделать?

Спасибо! Андрей

Ответы [ 6 ]

1 голос
/ 21 декабря 2009

Если бы у меня был выбор дизайна таблицы, и следующие утверждения верны:

  • Вы знаете максимальное количество вариантов ответа на вопрос /
  • Каждый выбор просто проверяется / не проверяется.
  • Каждый ответ должен быть классифицирован как правильный / неправильный, а не отмечен какой-либо шкалой. (Вроде на 70% верно.)

Затем, учитывая производительность, я бы рассмотрел следующую таблицу вместо представленной вами:

QuestionAnswers
(
  UserID int,
  QuestionID int,
  Choice1 bool,
  Choice2 bool,
  ...
  ChoiceMax bool
)

Да, это уродливо с точки зрения нормализации, но эта денормализация снизит производительность и упростит запросы - всего одно обновление / вставка для одного вопроса. (И я обновил бы сначала и вставил бы, только если затронутые строки равны нулю.)

Также определение правильности ответа будет также более простым - со следующей таблицей:

QuestionCorrectAnswers
(
  QuestionID int,
  Choice1 bool,
  Choice2 bool,
  ...
  ChoiceMax bool
)

Все, что вам нужно сделать, это просто найти строку в QuestionCorrectAnswers с той же комбинацией вариантов, что и пользователь.

0 голосов
/ 24 июня 2010

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

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

0 голосов
/ 02 марта 2010

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

CustomerName
(
    name_prefix
    name_first
    name_mi
    name_last
    name_suffix
    city
    state
    zip
)

То же, что и

QuestionAnswers
(
   Q1answer1
   Q1answer2
   Q1answerN
)

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

0 голосов
/ 26 декабря 2009

Это простое решение: Каждый [Ответ] должен иметь целочисленное значение (бит), и это значение уникально для текущего Вопроса. Например, у вас есть Вопрос1 и четыре предопределенных ответа:

[Ответ] [Значение бита]

answer1 0x00001

answer2 0x00002

answer3 0x00004

answer4 0x00008 ...

Итак, ваш SQL INSERT / UPDATE будет:

declare @checkedMask int
set @checkedMask = 0x00009 -- answer 1 and answer 4 are checked
declare @questionId int
set @questionId = 1

- удалить

delete
--select r.* 
r 
from QuestionResult r 
    inner join QuestionAnswer a  
        on r.QuestionId = a.QuestionId and r.AnswerId = a.AnswerId
where r.QuestionId = @questionId
 and (a.mask & @checkedMask) = 0

- вставить

insert QuestionResult (AnswerId, QuestionId)
    select
        AnswerId,
        QuestionId
    from QuestionAnswer a
       where a.QuestionId = @questionId
         and (a.mask & @checkedMask) > 0
         and not exists(select AnswerId from QuestionResult r 
                where r.QuestionId = @questionId and r.AnswerId = a.AnswerId)
0 голосов
/ 21 декабря 2009

Андрей. Если пользователь (идентификатор пользователя = 1) выбирает варианты a (answerid = 1) & b (answerid = 2) для вопроса 1 (questionid = 1), а затем переключается на c (a-id = 3) & d (a-id = 4), вам нужно будет проверить, затем удалить старое и добавить новое. Если вы решите следовать другому подходу, вы не будете проверять, существует ли конкретная запись (чтобы ее можно было обновить), вы просто удалите старые записи и вставите новые. В любом случае, поскольку вы не храните какие-либо столбцы идентификаторов, я бы выбрал последний подход.

0 голосов
/ 21 декабря 2009

Если вопросы всегда одинаковы, то вы никогда ничего не удалите - просто запустите запрос на обновление для всех измененных ответов.

Update QuestionAnswers
SET AnswerID = @AnswerID
WHERE UserID = @UserID AND QuestionID = @QuestionID

Если по какой-то причине вам все еще нужно выполнить какое-либо удаление / вставку - я бы проверил, какие Идентификаторы вопросов уже существуют (для данного идентификатора пользователя), поэтому вы выполняете как минимум удаление / вставку.

Обновления выполняются намного быстрее, чем «Удалить», а затем «Вставить», плюс вы не увеличиваете количество столбцов идентификации.

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

...