Высокопроизводительная вики-схема
-
12-09-2019 - |
Вопрос
Я использую MS SQL Server 2005.
Какая схема лучше всего подходит для Wiki-подобной системы?где пользователи редактируют/пересматривают материалы, а система отслеживает эти материалы.
Допустим, мы создаем простую систему на основе Wiki.Будет отслеживать каждую редакцию, а также просмотры и последние действия по каждой ревизии.На других экранах система отобразит «Последние публикации» и «Самые просматриваемые», а также поиск по названию.
Моя текущая схема (и я знаю, что она плоха) использует одну таблицу.Когда мне нужно просмотреть «Последние отправленные материалы», я сортирую их по «LatestActivity», группирую по «DocumentTitle», а затем беру первые N записей.Я предполагаю, что большая группировка (особенно группировка по nvarchar) — это плохая новость.Для перечисления наиболее просматриваемых я делаю то же самое:сортировать по представлениям, группировать по имени, брать первые N записей.Большую часть времени я также буду использовать «WHERE DocumentName LIKE '%QUERY-HERE%'».
Моя текущая схема — «Версия 1», см. ниже:альтернативный текст http://www.anaimi.com/junk/schemaquestion.png
Я предполагаю, что это неприемлемо.Поэтому я пытаюсь придумать другой/более эффективный дизайн.Как вам версия 2?Во второй версии я получаю преимущество группировки по WikiHeadId, который является числом - я предполагаю, что группировка по числу лучше, чем nvarchar.
Или крайний случай — версия 3, в которой я не буду группировать, но она имеет ряд недостатков, таких как дублирование значений, сохранение этих значений в коде и т. д.
Или существует ли лучшая/известная схема для таких систем?
Спасибо.
(перенесено из ServerFault - я думаю, что это скорее вопрос разработки, чем вопрос ИТ)
Решение
Во-первых (и из любопытства), как текущая схема указывает на текущую версию?У вас есть несколько записей «Вики-документ» с одним и тем же названием документа?
Мне также неясно, зачем вам нужна «LastActivity» на уровне версии.Я не понимаю, как «LastActivity» соответствует концепции «Версии» - в большинство вики, «версии» доступны для однократной записи:если вы изменяете версию, вы создаете новый версию, поэтому концепция значения последнего обновленного типа в версии бессмысленна — на самом деле это просто «дата создания».
На самом деле «естественная» схема вашего дизайна — №2.Лично я немного поклонник старой аксиомы БД: «нормализуй, пока не станет больно, затем денормализуй, пока не заработает».№2 — более чистый и приятный дизайн (простой, без дублирования), и если у вас нет срочной причины денормализовать его до версии 3, я бы не стал заморачиваться.
В конечном итоге дело сводится к следующему:Вы беспокоитесь о «более производительном» дизайне, потому что заметили проблемы с производительностью или потому, что гипотетически мощь есть немного?Нет никакой реальной причины, по которой №2 не должен работать хорошо.Группировка не обязательно является плохой новостью для SQL Server — на самом деле, если для запроса имеется подходящий индекс покрытия, он может работать очень хорошо, поскольку можно просто перейти к определенному уровню индекса, чтобы найти сгруппированные значения, а затем использовать остальные столбцы индекса будут использоваться для MIN/MAX/что угодно.Группировка по NVARCHAR не так уж и плоха — если она не является проблемой, не беспокойтесь об этом, хотя (недвоичные) параметры сортировки могут немного усложнить задачу — но в версии 2, где вам нужно GROUP BY вы можете сделать это по WikiHeadId, верно?
Одна вещь, которая может облегчить жизнь, если вы выполняете много операций над текущей версией (а я предполагаю, что вы это сделали), чтобы добавить FK обратно из таблицы заголовка в таблицу тела, указывая текущую версию.Если вы хотите просмотреть текущие версии с наибольшим количеством обращений, с номером 2 в его нынешнем виде это может быть:
SELECT TOP ...
FROM WikiHead
INNER JOIN
(SELECT WikiHeadId, MAX(WikiBodyVersion) /* or LastUpdated? */ AS Latest
FROM WikiBody GROUP BY WikiHeadId) AS LatestVersions
INNER JOIN WikiBody ON
(Latest.WikiHeadId = WikiBody.WikiHeadId)
AND (WikiBody.WikiBodyVersion = LatestVersions.Latest)
ORDER BY
Views DESC
или альтернативно
...
INNER JOIN WikiBody ON
(WikiHead.WikiHeadId = WikiBody.WikiHeadId)
AND (WikiBody.WikiBodyVersion =
(SELECT MAX(WikiBodyVersion) FROM WikiBody WHERE WikiBody.WikiHeadId = WikiHead.WikiHeadId)
...
и то, и другое отвратительно.Если WikiHead сохраняет указатель на текущую версию, это просто
...
INNER JOIN WikiBody ON
(WikiHead.WikiHeadId = WikiBody.WikiHeadId)
AND (WikiHead.Latest = WikiBody.WikiBodyVersion)
...
или что-то еще, что может быть полезной денормализацией только потому, что это облегчает вашу жизнь, а не для производительности.