Дизайн базы данных: несколько таблиц по сравнению с одной таблицей
Я создаю сайт, где есть различные типы элементов, такие как блоги, сообщения, статьи и т.д. Пользователь может установить любой из них в качестве своего любимого. Теперь, когда я подхожу к этой вещи, у меня есть две опции
- Создайте таблицу для избранных пользователей для каждого типа объектов.
- Создайте общую таблицу для всех типов объектов для всех пользователей.
Проблема с 1-й структурой заключается в том, что мне придется запрашивать множество таблиц для отображения избранных данных определенного пользователя. Но это позволит мне легко группировать фаворитов в разные категории.
Однако, если мне нужно показать все избранные на одной странице и объединить их все, отсортированные по времени, то это становится трудным. Но если я использую вторую модель, я могу легко получить последние избранные, а также группировать их в соответствии с типом объекта, это не сложно, но у меня будет один большой сайт в целом.
Какая из двух стратегий будет более масштабируемой.
Первый содержит несколько запросов к базе данных, а второй - влечет за собой большую отдельную таблицу.
Если это помогает, я использую MySql
Ответы
Ответ 1
Кажется, что вы уже знаете ответ, но помните, что системы, которые вы разрабатываете, просто модифицировать, поскольку бизнес-модели всегда меняются со временем или они в конечном итоге терпят неудачу (это обобщение, но вы получаете идею). Следствием этого является то, что если вы создадите жесткую модель, быструю или медленную, жесткую, изменения будут сложнее, и конечный пользователь не увидит разницы, поэтому никаких изменений в деньгах и счастье не будет достигнуто, если это не очень плохое изменение.
Ваша проблема не техническая, так как запрос работает на движке, но более философский, легко меняется по сравнению с кажущейся скоростью.
Спросите себя, какое преимущество имеет нормализованная база данных? Подумайте о чистой архитектуре и дизайне, производительность - это наименьшая проблема в сегодняшнем мире, поскольку обработка также дешевле и хранение. Но дизайн дорог.
Нормализация была сделана для создания систем, которые не зависят от решений в последний момент, а от процесса структурированного проектирования.
Большие таблицы не очень важны для MySql, но они очень важны для поддержания, модификации и расширения. Это не просто добавление еще одного столбца, это о жесткой структуре самих данных. Со временем вы просто добавите столбцы, содержащие индексы, и эти индексы будут указывать на маленькие таблицы. В любом случае MySql будет вспахивать все эти данные.
Поэтому я пойду за первым, много маленьких таблиц, многие-ко-многим.
Ответ 2
У меня есть этот дизайн на моем сайте. Мои модули: новости, статьи, видео, фотографии, загрузки, обзоры, викторины, опросы и т.д. Все в отдельных таблицах. У меня есть таблица с симпатией, в которой пользователям может понравиться или не понравиться сообщение (в вашем случае избранное). Запрос для их получения не так уж и сложный.
Во-первых, большинство MOST моих таблиц для модулей структурированы одинаково:
- ID
- название
- Содержание
- user_id (автор)
- Дата
- и т.д.
за некоторыми исключениями, так что иногда название называется вопросом или нет столбца содержимого. Это не вызывает никаких проблем.
Мои таблицы нравится так:
- ID
- page_id
- module_id (в какой таблице это произошло... У меня есть таблица модулей, где каждый модуль имеет заголовок, связанный идентификатор, каталог и т.д.)
- post_id (соответствует идентификатору таблицы модулей)
- user_id (пользователь, который понравился или опубликовал)
- status (0 = like, 1 = dislike)
- дата (когда симпатия/неприятие произошло)
Пример таблицы модулей:
- ID
- название
- каталог
- post_type
Пример
id title directory post_type
1 News news news
2 Episode Guide episodes episode
3 Albums discography/albums album
По существу у вас будет аналогичная настройка, изменяющая структуру таблицы, если это необходимо для ваших нужд.
Запрос для получения всех понравившихся или избранных для определенного пользователя:
$getlikes = mysql_query("SELECT DISTINCT post_id, module_id, page_id FROM likes WHERE user_id = $profile_id ORDER BY id DESC LIMIT $offset, $likes_limit", $conn);
$likes = mysql_num_rows($getlikes);
if($likes == "0"){
echo "<br><Center>$profile_username does not have any liked posts at this time.</center><BR>";
}
else {
echo "<table width='100%' cellspacing='0' cellpadding='5'>
<Tr><th>Post</th><th align='center'>Module</th><th align='center'>Page</th><tr>";
while ($rowlikes = mysql_fetch_assoc($getlikes)) {
// echo data
$like_page_id = $rowlikes['page_id'];
$like_module_id = $rowlikes['module_id'];
$like_post_id = $rowlikes['post_id'];
// different modules have different fields for the "title", most are called title but quotes is called "content" and polls is called "questions"
if($like_module_id == "11"){
$field = "question";
}
elseif($like_module_id == "19"){
$field = "content";
}
else{
$field = "title";
}
// FUNCTIONS
PostURL($like_page_id, $like_module_id, $like_post_id);
ModTitle($like_module_id);
ModTable($like_module_id);
ModURL($like_page_id, $like_module_id);
fpgURL($like_page_id);
$getpostinfo = mysql_query("SELECT $field AS field FROM $mod_table WHERE id = $like_post_id", $conn);
$rowpostinfo = mysql_fetch_assoc($getpostinfo);
$like_post_title = $rowpostinfo['field'];
// Using my "tiny" function to shorten the title if the module is "Quotes"
if($like_module_id == "19"){
Tiny($like_post_title, "75");
$like_post_title = "\"$tiny\"";
}
if(!$like_post_title){
$like_post_title = "<i>Unknown</i>";
}
else {
$like_post_title = "<a href='$post_url'>$like_post_title</a>";
}
echo "<tr class='$altrow'>
<td>$like_post_title</td>
<td align='center'><a href='$mod_url'>$mod_title</a></td>
<td align='center'>$fpg_url</td>
</tr>";
$altrow = ($altrow == 'altrow')?'':'altrow';
} // end while
echo "<tr><Td align='center' colspan='3'>";
// FUNCTIONS - Pagination links
PaginationLinks("$cs_url/users/$profile_id", "likes");
echo "</td></tr></table>";
} // end else if no likes
Хорошо, что вам может быть трудно понять, поскольку у меня есть много собственных переменных, но в основном он получает идентификатор модуля и идентификатор сообщения из таблицы lik, а затем запускает запрос, чтобы получить заголовок сообщения и любые другие info Я хочу, как оригинальный автор.
У меня есть функции "модуля", которые возвратят URL-адрес или заголовок модуля, если вы предоставите ему идентификатор.
Ответ 3
Так что, если я не ошибаюсь, вы пытаетесь создать таблицу Favorites
чтобы собрать любимые элементы пользователя, верно? Если это так, вам понадобится как минимум две таблицы.
Типы: типы ресурсов.
+----+---------+
| ID | Name |
+----+---------+
| 0 | blog |
| 1 | post |
| 2 | article |
| 3 | photo |
| 4 | video |
+----+---------+
Избранное: самая важная часть системы "Избранное", это своего рода карта отношений.
+--------+----------+--------------+
| UserID | TargetID | TargetTypeID |
+--------+----------+--------------+
| 941 | 1 | 0 |
| 6 | 935 | 1 |
| 26 | 51 | 4 |
| 7 | 87 | 2 |
+--------+----------+--------------+
Сообщения: в примере таблицы сообщений вы также можете иметь таблицы Blogs
или Photos
и Albums
.
+-----+------------------+
| ID | Title |
+-----+------------------+
| 0 | This is my post! |
| 51 | Oh, how are you? |
| 935 | Hello, world! |
+-----+------------------+
Теперь SQL-запрос может быть таким (непроверенным):
-- Get the posts
SELECT p.*
FROM Posts p
LEFT JOIN Favorites f
-- Which are favorited by the user 6
ON f.UserID = 6
-- Also get the type id of the 'post',
-- so we can specify the favorite type of the favorite items
AND f.TargetTypeID = (
SELECT ID
FROM Types
WHERE Name = 'post'
)
-- Make sure we only get the posts which are favorited by the user.
WHERE p.ID = f.TargetID
С помощью SQL-запроса, приведенного выше, вы можете получить избранные сообщения, которым пользуется ID 6.
+-----+------------------+
| ID | Title |
+-----+------------------+
| 935 | Hello, world! |
+-----+------------------+