#php #mysql #database #database-design #one-to-many
#php #mysql #База данных #database-design #один ко многим
Вопрос:
У меня есть приложение, которое предназначено для совместного использования шкафов между пользователями. Идея проста, участники публикуют свои материалы, другие могут комментировать или сохранять их, нажимая кнопку «Мне нравится».
У меня есть три таблицы:
Продукты:
------------- ------------- ------ ----- ------------------- ----------------
| Field | Type | Null | Key | Default | Extra |
------------- ------------- ------ ----- ------------------- ----------------
| ID | int(11) | NO | PRI | NULL | auto_increment |
| NAME | varchar(16) | NO | | NULL | |
| FBID | varchar(32) | NO | | NULL | |
| TITLE | text | NO | | NULL | |
| DESCRIPTION | text | NO | | NULL | |
| BRAND | varchar(16) | NO | | NULL | |
| SIZE | varchar(12) | NO | | NULL | |
| CATEGORY | varchar(22) | NO | | NULL | |
| COLOR | varchar(12) | NO | | NULL | |
| COND | varchar(12) | NO | | NULL | |
| ORIGPRICE | varchar(8) | NO | | 0 | |
| SALEPRICE | varchar(8) | NO | | 0 | |
| IMAGES | text | NO | | NULL | |
| TIMESTAMP | timestamp | NO | | CURRENT_TIMESTAMP | |
| SOLDSTATUS | varchar(1) | NO | | 0 | |
| VIEWS | int(6) | NO | | 0 | |
| RECOMMENDED | varchar(1) | NO | | 0 | |
------------- ------------- ------ ----- ------------------- ----------------
Нравится:
-------- ------------- ------ ----- --------- ----------------
| Field | Type | Null | Key | Default | Extra |
-------- ------------- ------ ----- --------- ----------------
| ID | int(11) | NO | PRI | NULL | auto_increment |
| PRODID | varchar(11) | NO | | NULL | |
| FBID | varchar(32) | NO | | NULL | |
-------- ------------- ------ ----- --------- ----------------
Комментарии:
----------- ------------- ------ ----- ------------------- ----------------
| Field | Type | Null | Key | Default | Extra |
----------- ------------- ------ ----- ------------------- ----------------
| ID | int(11) | NO | PRI | NULL | auto_increment |
| PRODID | int(11) | NO | | NULL | |
| NAME | varchar(32) | NO | | NULL | |
| FBID | varchar(32) | NO | | NULL | |
| COMMENT | text | NO | | NULL | |
| IMGPATH | text | NO | | NULL | |
| TIMESTAMP | timestamp | NO | | CURRENT_TIMESTAMP | |
----------- ------------- ------ ----- ------------------- ----------------
До сих пор (и я думаю, что здесь я ошибся), чтобы отобразить продукты на главной странице вместе с количеством лайков / комментариев, я делал подзапросы, используя отдельные функции, встроенные в запрос, например:
$query = "SELECT * FORM PRODUCTS"
if($result = mysqli_query($mysqli, $query)) {
while($row = mysqli_fetch_assoc($result)){
$jsonRow = array(
'sqlId' => $row['ID'],
'name' => $row['NAME'],
'likecount' => countLikes($row['ID'], $mysqli),
'commentcount' => countComments($row['ID'], $mysqli)
);
}
Теперь, после 10.000 записей, для повышения производительности я попытался:
- Объединить все три таблицы, но таким образом я могу группировать / подсчитывать вещи один раз для ЛАЙКОВ без возможности одновременного подсчета КОММЕНТАРИЕВ.
- Или создать новые столбцы для: LIKESCOUNT внутри таблицы PRODUCTS и обновлять их каждый раз, когда пользователю нравится продукт, подсчитывая появления продукта (PRODID) в таблице LIKES .
Любые другие мысли о том, как сделать это правильно? Спасибо
Комментарии:
1. что такое FBID? также не могли бы вы изменить свои скриншоты на текст, пожалуйста
2. FBID сокращение от facebook id. Я пытался добавить текстовые сведения о БД, но они не будут правильно форматироваться, я попробую еще раз
3. Хороший распространенный способ решить эту проблему — использовать ваш подход 2, он же «кэш счетчика». Единственное изменение, которое я бы сделал, это не пересчитывать лайки каждый раз, когда добавляется новый лайк, а увеличивать при создании лайка и уменьшать при его уничтожении (если это есть в вашем приложении). Почему у вас это не сработало?
4. в будущем не используйте
DESCRIBE
для отображения схемы. Скорее, покажите вывод изshow create table myTableName
5. Много полезных комментариев. Если я могу добавить еще пару, вы используете заглавные буквы для имен полей. Соглашение заключается в использовании нижнего регистра. Не беспокойтесь об изменении этих таблиц, но при создании новой базы данных в будущем, пожалуйста, имейте это в виду.
Ответ №1:
Объединить все три таблицы, но таким образом я могу группировать / подсчитывать вещи один раз для ЛАЙКОВ без возможности одновременного подсчета КОММЕНТАРИЕВ.
Вы можете подсчитывать ЛАЙКИ и КОММЕНТАРИИ в одном запросе. Но вам нужно использовать подзапросы (чтобы не создавать перекрестное соединение между ЛАЙКАМИ и КОММЕНТАРИЯМИ).
select sub.*, count(l.PRODID) as likecount
from (
select p.*, count(c.PRODID) as commentcount
from products p
left join comments c on c.PRODID = p.ID
group by p.ID
) sub
left join likes l on l.PRODID = sub.ID
group by sub.ID
Вы также можете подсчитать комментарии и лайки в подвыборке.
select p.*,
(
select count(*)
from comments c
where c.PRODID = p.ID
) as commentcount,
(
select count(*)
from likes l
where l.PRODID = p.ID
) as likecount
from products p
Но я бы, вероятно, выполнил три запроса
select * from products;
select PRODID, count(*) as commentcount from comments group by PRODID;
select PRODID, count(*) as likecount from likes group by PRODID;
и объедините результаты в PHP.
$products = array();
$query = "SELECT * FORM PRODUCTS";
$result = $mysqli->query($query);
while($row = $result->fetch_assoc()) {
$products[$row['ID']] = array(
'sqlId' => $row['ID'],
'name' => $row['NAME'],
'likecount' => 0,
'commentcount' => 0
);
}
$query = "SELECT PRODID, COUNT(*) as commentcount FROM comments GROUP BY PRODID";
$result = $mysqli->query($query);
while($row = $result->fetch_assoc()) {
$products[$row['PRODID']]['commentcount'] = $row['commentcount'];
}
$query = "SELECT PRODID, COUNT(*) as likecount FROM likes GROUP BY PRODID";
$result = $mysqli->query($query);
while($row = $result->fetch_assoc()) {
$products[$row['PRODID']]['likecount'] = $row['likecount'];
}
Комментарии:
1. Три возможных решения в одном ответе, слишком хорошо, чтобы быть правдой! Спасибо, чувак, я буду экспериментировать со всеми из них! 🙂
2. Еще одно спасибо, это работает как шарм. Но не могли бы вы помочь мне понять 2 вещи? Можно ли ссылаться на таблицу, используя только ее первый символ: «c.PRODID»? Или вы инициализируете c здесь: «присоединяйтесь к комментариям c на c.PRODID»? И еще одна вещь » sub. * » — это команда, или она будет результатом одного из подзапросов? Я немного смущен: P
3. Вы можете присвоить каждой таблице в запросе псевдоним.
JOIN comments c
также может быть записано какJOIN comments AS c
.sub
также является псевдонимом таблицы для подзапроса. Таким образом, вы можете ссылаться на столбцы из результата подзапроса с помощьюsub.column1
.4. Спасибо за полезную информацию!