Есть скрипт просчёта статистики неважно чего, там каждый день просчитывается поочерёдно. И есть юзер со статистикой за 635 дней, которая просчитывается ооочень долго при открытии страницы. Я решил сделать систему кэширования для всего этого. В цикле где просчитываются дни, статистику каждого дня я стал писать в базу. Упрощённый пример: Было: PHP: foreach($days as $day) { // do stuff $out .= 'test'; } echo $out; Стало: PHP: foreach($days as $day) { // do stuff $stats = 'test'; $out .= $stats; // запись кэша, если нужно $query = $db->query("SELECT `id` FROM `stats` WHERE `user`=$user AND `day`=$day"); $row = mysqli_fetch_array($query, MYSQLI_ASSOC); if (!$row['id']) { $db->query("INSERT INTO `stats` SET `stats`='$stats' WHERE `user`=$user AND `day`=$day"); } } echo $out; Итог - страница стала вешаться где-то на 140-м дне, хотя раньше статистика за 635 дней могла просчитаться за раз, хоть и долго прогружалась. Что я сделал не так? Почему вторая запись гораздо нагружает сервер в ынацать раз сильнее, чем первая? Может есть способ выполнять SQL-запросы не в цикле, а собрать их в переменную и выполнить один раз в конце?
А как такой запрос составить? Там наверно не получится одним запросом, потому что там могут быть как INSERT, так и UPDATE. В функции есть флаг $cache - если он false, значит кэш надо пересчитать с нуля, то есть сделать UPDATE существующих дней и сделать INSERT недостающих. Выглядит это так сейчас. Как тут вынести запросы за цикл - хз. PHP: foreach($days as $day) { // do stuff $stats = 'test'; $out .= $stats; // запись кэша, если нужно $query = $db->query("SELECT `id` FROM `stats` WHERE `user`=$user AND `day`=$day"); $row = mysqli_fetch_array($query, MYSQLI_ASSOC); if (!$row['id']) { $db->query("INSERT INTO `stats` SET `stats`='$stats' WHERE `user`=$user AND `day`=$day"); } else { if (!$cache) { $db->query("UPDATE `stats` SET `stats`='$stats' WHERE `user`=$user AND `day`=$day"); } } } echo $out;
@Ganzal А так будет не проще в плане русорсо-потребления? PHP: if (!$cache) { $db->query("DELETE FROM `stats` WHERE `user`=$user"); } foreach($days as $day) { // do stuff $stats = 'test'; $out .= $stats; // запись кэша, если нужно $query = $db->query("SELECT `id` FROM `stats` WHERE `user`=$user AND `day`=$day"); $row = mysqli_fetch_array($query, MYSQLI_ASSOC); if (!$row['id']) { $db->query("INSERT INTO `stats` SET `stats`='$stats' WHERE `user`=$user AND `day`=$day"); } } echo $out; Я бы хотел сделать что-то такое, но хз можно ли так. PHP: if (!$cache) { $db->query("DELETE FROM `stats` WHERE `user`=$user"); } foreach($days as $day) { // do stuff $stats = 'test'; $out .= $stats; // запись кэша, если нужно $query = $db->query("SELECT `id` FROM `stats` WHERE `user`=$user AND `day`=$day"); $row = mysqli_fetch_array($query, MYSQLI_ASSOC); if (!$row['id']) { $sql .= "INSERT INTO `stats` SET `stats`='$stats' WHERE `user`=$user AND `day`=$day ;"; } } $db->query($sql); echo $out;
Не суть, там выполняется километровый код расчёта кучи всего. Цикл довольно нагруженный, но он выполнялся за раз всё-таки. Вешаться стало когда я добавил в цикл вот эти SQL-запросы с записью кэша.
Да не за что. Тебе пытались подсказать, но тебе не суть. Ты хочешь вот так - делай вот так. Ты делаешь ПРАВИЛЬНО. Устраивает? Подбодрил?
@Ganzal Ты херню несёшь, парень. Я обратился с конкретной проблемой - сократить нажористость SQL-запросов. Вместо этого тебе зачем-то надо копаться в остальном моём коде. Меня интересует, есть ли разница по нагрузки между этими подходами: PHP: $numbs = array(1,2,3); foreach($numbs as $numb) { $db->query("INSERT INTO `test` SET `field1`='example', `field2`=$numb "); } PHP: $numbs = array(1,2,3); foreach($numbs as $numb) { $sql[] = "('example', $numb)"; } $sql = implode(',', $sql); // = "('example', 1), ('example', 2), ('example', 3)" $db->query("INSERT INTO `test` (`field1`, `field2`) VALUES $sql ;"); Если не знаешь, то зачем что-то писать вообще? Чтобы повыпендриваться в разделе "для новичков"?
Если ты хочешь спросить "быстрее выполнить один запрос вставки или миллион" то да, быстрее будет работать один или несколько запросов вставки с пакетами данных. Мой вопрос про ду стаф был направлен на попытку выяснить нельзя ли вообще один запрос выполнить с перекачкой из одной таблицы, агрегации и вставки-обновления другой. Голову включи перед тем как отвечать.
@NerdRage 2 способ более сообразителен, нежели в цикле насиловать запросами БД. По сути ничего особого нет, что в первом и во 2ом. Наверное в PDO было бы легче без сбора данных эксешить: PHP: $numbs = array ( 1, 2, 3 ); $PDO = PDO::prepare( "INSERT INTO test ( 'field1', 'field2' ) VALUES ( ?, ? )" ); foreach ( $numbs AS $numb ) { $PDO -> execute( array ( 'example', $numb ) ); }
Выясняются новые подробности. Оказывается, у меня на локалке скрипт вешался, потому что у меня стоит PHP 7. А на хостинге он при этом нормально отрабатывает, там PHP 5.3. Вот эти директивы там и там одинаковые: Код (Text): max_execution_time = 60 max_input_time = -1 max_input_nesting_level = 64 max_input_vars = 3000 memory_limit = 128M Вот phpinfo() с хостинга: http://185.5.248.25/hosting.htm Вот с локалки: http://185.5.248.25/local.htm
Короче я перешёл тестить на локалку - под OpenServer вешается, а под Denwer нет. При этом версию PHP я поставил идентичную, с одинаковым php.ini - 5.3.29. Даже не знаю из-за чего ещё это может быть. Версия mysql там и там 5.5. Версии апача только отличаются - 2.2 в OpenServer и 2.0 в Denwer.
@NerdRage бррр.... код вешает не правильный алгоритм действий, дебаж! --- Добавлено --- вот этот чувак знает больше чем я с тобой вместе взятый и ещё таких по три, он конечно любитель потроллить, но он попытался понять, что у тебя в коде происходит. Ты как себе представляешь помощь тебе, без понимания логики твоего кода? Я тебе так скажу твой тут супер крутой алгоритм поверь, который ты там прячешь, нахер не кому не усрался. Знаешь сколько таких крутых в интернете? А помочь без полного понимания логики твоего кода не возможно, можно лишь гадать и ванговать, ну и на синтаксис посмотреть и сказать где у тебя там ошибка, но тоже может сделать и ide и debug php. --- Добавлено --- @NerdRageИ это не истерика, это факт хочешь помощи, расскажи логику своей программы и тебе помогут скажут где что не так и как лучше сделать, иначе это как гадать на кофейной гущи.
Свой код я не шарю не потому что я боюсь, что мою мега-разработку стырят, а потому что он километровый, он даже в сообщение на форуме вряд ли влезет - кому-то охота вчитываться в такое? Я специально упростил пример по максимуму, чтобы не выносить людям мозг. Вместо этого мозг начали выносить мне. Короче, если свести всё к изменениям, которые я делал, то тут два варианта: 1. Добавил запись в БД в цикле. 2. Переделал запросы в БД с MySQL на MySQLi. То есть, теперь формат такой: PHP: function query($query) { return mysqli_query($this->db, $query); } Может в этом причина кстати? Может устаревший формат mysql_query быстрее?
Использую, для эскейпов просто отдельная функция. Не помню зачем я так сделал. Но теперь уже, работает - не трогай.
Вчера выложил систему на боевой, ночью просчитывался кэш - 413 тысяч попугаев вместо обычных 726. И это он ещё на половину не просчитался. Страницы всё-таки стали открываться на много медленнее, когда чтение из кэша выключено. А должно быть тоже самое. Есть какой-то способ померить у себя на локалке нагрузку на MySQL, количество запросов и всё такое? У меня есть старая версия скрипта, которая работала быстро и новая версия, которая работает медленно. Хочу сравнить по нагрузке, и методом перебора выяснить что вызывает затупливание. Я только знаю как посчитать время выполнения PHP-скрипта.
Замерь куски кода, так найдёшь которые долго работают. Ещё есть xdebug там он может создавать отчёт потом его можно открыть и посмотреть в графическом виде например, что дольше всего выполнялось.