Моя модель базы данных (отстой) вызывает головную боль, как ее улучшить?

#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 записей, для повышения производительности я попытался:

  1. Объединить все три таблицы, но таким образом я могу группировать / подсчитывать вещи один раз для ЛАЙКОВ без возможности одновременного подсчета КОММЕНТАРИЕВ.
  2. Или создать новые столбцы для: 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. Спасибо за полезную информацию!