@vLaZoV

Почему медленно загружается страница на PHP, которая берёт данные из MySQL?

На странице статьи на форуме скрипт должен выводить все комментарии к посту учитывая их иерархию. Я реализовал это самым просты способом: написал функцию-генератор, который возвращает запись из БД при каждой итерации цикла foreach. Реализуется класс для работы с БД PDO. Всё работает, комменты выводит, но страница грузится оооочень долго. Плюс в консоли выходит варнинг:
Unchecked runtime.lastError: The message port closed before a response was received. article.php:1

Два вопроса:
1. Почему это происходит, и как это пофиксить?
2. Может ли это быть связано с тем, что у меня слабый ПК? Скрипт запускаю на localhost, т. к. реальный хост пока себе позволить не могу, да и незачем.

Собственно, связанные с вопросом участки кода:
<?php
function getComment($article_id, $parent, $pdo) {
    $order = $parent == 0 ? "DESC" : "ASC";
    
    $comments = $pdo->prepare("SELECT * FROM comments WHERE article_id = :article_id AND parent = :parent ORDER BY put_date $order");
    $comments->execute([
        "article_id" => $article_id,
        "parent" => $parent
    ]);
    while ($line = $comments->fetch(PDO::FETCH_ASSOC)) {
        yield $line;
        if(entryExists(getPDO(), $line["id"], "parent", "comments")) getComment($article_id, $line["id"], $pdo); // Этот участок пробовал убирать и проблема не ушла, так что это не из-за рекурсии
    }
}
?>

<!-- другой код... -->
<div class="comments_block">
    <? $pdo = getPDO();
        foreach (getComment($_GET["id"], 0, $pdo) as $line) { ?>
        <div class="comment">
            <!-- блок комментария, который использует данные из возвращённого $line -->
        </div>
    <? } ?>
</div>
<!-- другой код... -->

/*
entryExists() проверяет наличие записи в БД
getPDO() просто возвращает PDO-объект, сделал её для краткости
с этими функциями всё в порядке
*/


Что пробовал:
-Ограничить запрос в БД, т. е. сделать как бы разбиение по страницам
-Убрать весь остальной код, чтобы убедиться что проблема именно в комментариях
-Убрать рекурсию из функции, т. е. последнюю строчку 'if(entryExists...'
-Использовать fetchAll();
Ничего из этого не помогло. Помогите пожалуйста
  • Вопрос задан
  • 1123 просмотра
Пригласить эксперта
Ответы на вопрос 3
@Lex85
По моему опыту, дёргать таблицу в цикле — плохая идея. Попробуйте сначала получать все данные, а потом в цикле их разбирать.
Ответ написан
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
ORDER BY put_date ASC
больно ссуко( хотя может и не очень

индекс на парент убедись что есть. можно даже внешний ключ, похер что в одной таблице.

у тебя дерево вложенности. очень большое (больше 3-4 уровней вполне возможно) - да ещё и с огромным числом записей. делать его через
id,parent_id
это очень тяжело

тебе нужно делать отдельную таблицу
CommentsTree
id, comment_id, parent_id, depth, level

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

id, comment_id, parent_id, depth, level (левел можно в таблице комментов хранить а не в дереве, они одинаковые для конкретного коммента)
// это вот было
1, 1, 1, 0, 1 // читать как "коммент 1 родитель он же сам (1), дельта глубины 0, общий уровень 1"
2, 2, 2, 0, 2 // читать как "коммент 2 родитель он же сам (2), дельта глубины 0, общий уровень 2"
3, 2, 1, 1, 2 // читать как "коммент 1 родитель 1, дельта глубины 1, общий уровень 2"

// добавляем потомка к 2
4, 3, 3, 0, 3 // читать как "коммент 3 родитель он же сам (3), дельта глубины 0, общий уровень 3"
5, 3, 2, 0, 3 // читать как "коммент 3 родитель 2, дельта глубины 1, общий уровень 3"
6, 3, 1, 2, 3 // читать как "коммент 3 родитель 1, дельта глубины 2, общий уровень 3"

Потом из этой таблицы можно дернуть WHERE parent_id = :parent и получить все дерево

Если похожим образом будешь делать товары, которые кстати говоря бывают в двух категориях одновременно - то еще добавится поле category_path, где через точку (1.2.3) или в JSON ([1,2,3]) лежит путь до самого верха в качестве точки отсчета вместо category_id
Ответ написан
VladimirAndreev
@VladimirAndreev
php web dev
для начала - сделайте explain ваших запросов...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы