Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Fatal error при sql запросе 
V
    Опции темы
PoTaP0ff
Дата 8.10.2007, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 8.10.2007

Репутация: нет
Всего: нет



Вообщем начал я тут доделывать кое че на одном форуме, но из-за хостера в одном месте лагает из-за превышения лимита ресурсов. Есть 3 таблицы, в одной инфа о бане(ban_id, ban_userid, ban_ip, ban_email, ban_mod, ban_date, ban_forum, ban_text, ban_time; где ban_mod-id юзверя, который банил; ban_date-дата бана; ban_forum-id раздела, кде забанили; ban_text-причина бана; ban_time-длительность бана) во второй инфа о юзверях(нам от тудава нужны: user_id, username), ну и третья инфа о разделе(оттудава нужно: forum_name). Мне надо составить список забаненных юзверей в таком виде: имя забаненного юзверя|имя банившего|время бана|раздел|на сколько.
Всеб ничего, только проблема в том, что при sql запросе выскакиват ошибка:
Цитата

Fatal error: Maximum execution time of 30 seconds exceeded in ...\www\admin\admin_user_ban.php on line 406

сам запрос выглядет так:
Код

$sql = "SELECT b.*, u.username, f.forum_name, moders.username as mod_name
FROM " . BANLIST_TABLE . " b, " . USERS_TABLE . " moders, " . USERS_TABLE . " u, " . FORUMS_TABLE . " f
WHERE u.user_id = b.ban_userid AND moders.user_id = b.ban_mod
AND f.forum_id = b.ban_forum
OR b.ban_forum = 0
AND b.ban_userid <> 0
AND u.user_id <> " . ANONYMOUS . "
ORDER BY b.ban_id desc";

дальше вся обработка происходит в цикле:
Код

for($i = 0; $i < count($user_list); $i++)
{
$ban_time = create_date($board_config['default_dateformat'], $user_list[$i]['ban_date'] , $board_config['board_timezone']);
print $user_list[$i]['username'].' | '. $user_list[$i]['mod_name']. ' | '.$ban_time.' | '.$user_list[$i]['forum_name'].' | '. $user_list[$i]['ban_time'];
}

вот как раз в этом цикле и возникает ошибка, а номер стороки, которую показывает ошибка всегда рзный и колблеться внутри цикла.
вообщем делал пошти все, даже начальный скрипт херачил - открывает секунд через 20 еле-еле. Это все как я понял из-за объема информации, как с этим бороться, мож кто знает?
PM MAIL   Вверх
chin
Дата 8.10.2007, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 28.10.2006

Репутация: нет
Всего: нет



А сколько результатов запроса? В случае, если больше 100, есть смысл делать постраничку.
PM MAIL   Вверх
Glip
Дата 8.10.2007, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 473
Регистрация: 30.12.2006

Репутация: 1
Всего: 18



можно немного выйграть если count($user_list) посчитать один раз а не при каждом проходе цикла.
ну еще посмотреть explain запроса, может индексов навесить..


--------------------
user posted image
PM MAIL   Вверх
PoTaP0ff
Дата 8.10.2007, 21:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 8.10.2007

Репутация: нет
Всего: нет



chin, дофига, больше 500 точна буит.
Glip, поподробнее плз.

Это сообщение отредактировал(а) PoTaP0ff - 8.10.2007, 21:06
PM MAIL   Вверх
chin
Дата 9.10.2007, 00:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 28.10.2006

Репутация: нет
Всего: нет



Если скрипт используется часто, постраничку однозначно.
Замеряйте время самого SQL запроса, делается это так:
Код

$time = array_sum(explode(" ", microtime()));
// ... sql запрос
$time = array_sum(explode(" ", microtime())) - $time;
echo $time;

Для того, чтобы сделать EXPLAIN, просто напишите это слово перед SELECT в своем запросе, и посмотрите результат. А лучше всего его в студию.

Glip, 
Оптимизация с count() - спички по сравнению с его запросом ;)

Это сообщение отредактировал(а) chin - 9.10.2007, 00:29
PM MAIL   Вверх
PoTaP0ff
Дата 9.10.2007, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 8.10.2007

Репутация: нет
Всего: нет



chin, вписал EXPLAIN перед SELECT, вот результат:
Цитата

table  type  possible_keys  key  key_len  ref  rows  Extra 
moders    ALL    PRIMARY    NULL    NULL  NULL    6    Using temporary; Using filesort
u    ALL    PRIMARY    NULL    NULL  NULL    6  
f    ALL    PRIMARY    NULL    NULL  NULL    3  
b    ALL    NULL  NULL    NULL  NULL    720    where used

Сам же запрос, без вывода на экран, выполняется
Цитата

7.3597481250763

Попробывал опять вывести на экран, снова время выполнения превышено:(
Мож правда индексвов понавешать? Тока расскажите поподробнее, как и че, я в sql не силен...
Вот тут мне предложили такой вариант:
Код

SELECT b.*, u.username, f.forum_name, moders.username as mod_name
FROM " . BANLIST_TABLE . " b " 
. " LEFT JOIN " . USERS_TABLE . " moders ON b.ban_mod = moders.user_id " 
. " LEFT JOIN " . USERS_TABLE . " u ON b.ban_userid = u.user_id " 
. " LEFT JOIN " . FORUMS_TABLE . " f ON b.ban_forum = f.forum_id
WHERE b.ban_userid <> 0
AND b.ban_userid <> " . ANONYMOUS . "
ORDER BY b.ban_id desc

воткнул этот запрос, получилось очень неплохо: 
Цитата

0.041857004165649

вместе с циклом обработал за:
Цитата

0.34096002578735

меня эт очень радует, но хотелось бы еще чье нить мнение услышать...

Это сообщение отредактировал(а) PoTaP0ff - 9.10.2007, 14:05
PM MAIL   Вверх
flashaa
Дата 10.10.2007, 10:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 796
Регистрация: 7.3.2006

Репутация: 2
Всего: 25



Glip совершенно верно говорит про count().

Проверка условия в for выполняется на каждой итерации цикла. Следовательно функция выполняется столько раз сколько эл-тов в массиве. С другой стороны, чем больше элементов, тем медленнее работает count(). Получаем то, что время выполнения этой конструкции растет в геометрической прогрессии при увеличении размера массива.
Вот, почитайте комменты на php.net - тут про это сказано - http://ru2.php.net/manual/en/function.count.php 

Код

NEVER USE IN CYCLES!

//size of $arr ~ 2000 elements

//wrong variant (Time exec ~ 19 sec)
for($i=0;$i<count($arr);$i++)
{
   ...
}

//right variant(Time exec ~ 0.2 sec)
$arr_size=count($arr);
for($i=0;$i<$arr_size;$i++)
{
   ...
}

PM MAIL   Вверх
sTa1kEr
Дата 10.10.2007, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 9
Всего: 146



PoTaP0ff, создайте индексы для полей b.ban_mod, b.ban_userid, b.ban_forum и самое главное сделайте поле b.ban_id первичным ключем! И приведите еще раз EXPLAIN.

flashaa, Все правильно, но вот цифры очень странные... 2000 раз взять count() от массива из 2000 элементов - 19 секунд?! Что за тормознутый сервер тогда был у этого юзера?!
Код

$arr = array_fill(0, 2000, 1);

$start = microtime(true);
for($i=0; $i < count($arr); $i++)
{
   $arr[$i] = 2;
}
echo microtime(true) - $start." sec\n";

$count = count($arr);
$start = microtime(true);
for($i=0; $i < $count; $i++)
{
   $arr[$i] = 3;
}
echo microtime(true) - $start." sec\n";

Результат
Код

0.00213479995728 sec
0.000816106796265 sec

Тот же самый тест, но для 200 000 записей
Код

0.226316928864 sec
0.0874929428101 sec


Это сообщение отредактировал(а) sTa1kEr - 10.10.2007, 15:38
PM MAIL   Вверх
flashaa
Дата 10.10.2007, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 796
Регистрация: 7.3.2006

Репутация: 2
Всего: 25



sTa1kEr, с чего Вы взяли, что именно count() cделал 19 сек? Что у него в цикле выполнялось - непонятно,  не указано. Факт в том, что с count() в условии for тот же самый цикл работал в 95 раз дольше.
PM MAIL   Вверх
sTa1kEr
Дата 10.10.2007, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 9
Всего: 146



Цитата(flashaa @  10.10.2007,  17:08 Найти цитируемый пост)
sTa1kEr, с чего Вы взяли, что именно count() cделал 19 сек? Что у него в цикле выполнялось - непонятно,  не указано.

Потому что иначе этот код не имеет смысла. Сравнивается скорость работы count(), а не непонятно какого кода замаскированного под многоточие. 

Цитата(flashaa @  10.10.2007,  17:08 Найти цитируемый пост)
Факт в том, что с count() в условии for тот же самый цикл работал в 95 раз дольше. 

Я очень сомневаюсь в достоверности этого факта. У меня в тесте получилось, что примерно в 3 раза дольше (причем не зависимо от количества элементов в массиве.) Я, конечно, предполагаю, что в этом коде такие цифры из-за того, что запускался он на какой-нибудь старой сырой версии PHP, но тогда нужно было писать это в баги, а не в комментарии мануала.

PS Сейчас запустил аналогичный тест в PHP 4.4.7 - там разница не более чем в 2 раза.
PM MAIL   Вверх
flashaa
Дата 10.10.2007, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 796
Регистрация: 7.3.2006

Репутация: 2
Всего: 25



А вы попробуйте mysql_connect вставить в цикл, вот один из моих результатов: 0.00959801673889 sec 0.221158981323 sec
PM MAIL   Вверх
sTa1kEr
Дата 10.10.2007, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 9
Всего: 146



Цитата(flashaa @  10.10.2007,  17:45 Найти цитируемый пост)
А вы попробуйте mysql_connect вставить в цикл, вот один из моих результатов: 0.00959801673889 sec 0.221158981323 sec 

Попробовал на 1000 итерациях.
Код
Код

function testFunc()
{
   $db = new mysqli("localhost", "root", "", "test");
   $db->query("SELECT NOW()");
   $db->close();
}

$arr = array_fill(0, 1000, 1);

$start = microtime(true);
for($i=0; $i < count($arr); $i++)
{
   testFunc();
}
echo microtime(true) - $start." sec\n";

$count = count($arr);

$start = microtime(true);
for($i=0; $i < $count; $i++)
{
   testFunc();
}
echo microtime(true) - $start." sec\n";

Результат
Код

9.04039812088 sec
9.01814508438 sec

То что значения массива и их типы могут повлиять на скорость count() - это я могу понять (все таки каждое значение надо проверить на null), но вот с чего вдруг код внутри цикла должен влиять на скорость работы???

Это сообщение отредактировал(а) sTa1kEr - 10.10.2007, 18:40
PM MAIL   Вверх
flashaa
Дата 11.10.2007, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 796
Регистрация: 7.3.2006

Репутация: 2
Всего: 25



Да, пожалуй, Вы правы на счет того что содержимое не влияет, да и время выполнения у меня каждый раз время разное - это показатель того, что на опыт сильно влияют другие факторы.
Отпостил результаты одного из случаев с большой разницей в числах.
Так что соглашусь с тем, что не count() скорее всего нагнал разницу, но использовать его следуеткак я писал

Это сообщение отредактировал(а) flashaa - 11.10.2007, 11:56
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Базы Данных | Следующая тема »


 




[ Время генерации скрипта: 0.4602 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.