Раз 100 запускал /?explain=1 с рассмотрением запросов. Все чисто. Когда этот запрос не буксует, все грузится в за 0.1-0.2 секунды.
А когда буксует, то это же время + время пробуксовки.
Разница вот она 120000 против 20000, и неважно сколько пользователей онлайн, просто таблица больше. Все упирается в БД а не в движок. Можно поставить модификатор отложеного запроса LOW_PRIORITY, если это MySQL, но может поможет…
такое бывает… может стоит поменять тип таблицы например на InnoDB они не блокируют всю таблицу при вставке. И еще параметры сервера стоит подкрутить, чтобы больше памяти было у БД.
Странно, но в на хостинге от джино есть статистика медленных запросов, и аналогичный запрос почему-то тоже там считается медленным
UPDATE reg SET last_time=NOW() WHERE id='2948';
Такое ощущение, что на сервере крутятся ещё сайты и mysql не держит нагрузку. 120000 записей — это уж точно не предел, хотя еще не известно, что в других таблицах
селект и апдейт для одной таблицы не может выполняться одновременно, ибо это может привести к колапсы и неверной выборке, поэтому они ставятся в очередь.
А вообще можно поизучать processlist и посмотреть почему так долго идет запрос и что делается перед ним.
как криво-то? я так понимаю там userid это PRIMARY KEY и всё.
вообще, elfiki хорошую идею подал, надо попробовать вынести время последнего пребывания в другую таблу.
В форуме более важную роль играет кол-во сообщений, форумов, дополнительные моды. Приведенный запрос абсолютно не причем, если по user_id есть ключ и 20, 120 тысяч тут не причем.
В качестве быстрого решения можно включить memcached, а вообще на форумах vbulletin.com, vbulletin.org есть темы с форумами-миллионниками. Там есть много ответов и решений
Поздравляю вы попали. Вы в курсе что при каждой операции записи лочится вся таблица? Просто потому что MyISAM не знает что такое транзакции. Если проблема именно в этом запросе то достаточно будет конвертнуть в InnoDB таблицу user и станет хорошо.
PS Вообще общий совет. Если у вас нет полнотекстового поиска в базе и много одновременных операций записи перейти на InnoDB. Правда предварительно подтюнив. Что тюнить и как можно посмотреть на MySQL Performance Blog. Ну и если все же MySQL не справляется рекомендуется мигрировать на PostgreSQL. Он лучше держит нагрузки и проще в обслуживании.
А причем тут VBulletin? Главное чтобы СУБД знало. В случае если транзакциями не управляют явно, ими управляет СУБД и каждый запрос обрабатывается в пределах одной транзакции. Это так называемый autocommit.
Вообще-то InnoDB может лочить одну строку именно из-за механизма транзакций. В MyISAM он отсутствует по этому требуется блокировать всю таблицу если требутеся избежать проблем с целостностью данных.
Решал схожую проблему, то есть у меня была конструкция вида:
UPDATE posts SET open = open + 1 WHERE id = 1;
При большом количестве запросов к базе данных (то есть когда qps подскакивал до 500 и выше) имел большие тормоза, это было связано с тем что базы MyISAM (соответственно — table lock) и отказаться от них не получаться (используется Full Text Search).
Потом пробывал разрулить ситуацию с HIGH_PRIORITY и LOW_PRIORITY, то есть UPDATE LOW_PRIORITY и SELECT HIGH_PRIORITY, но все равно сталкивался с проблемами медленно выполняемых запросов
Решил проблему с помощью следующей конструкции:
Вместо UPDATE делаем INSERT в другую таблицу:
INSERT post_cnt (id,dtime) VALUES (1,now())
А при SELECT-е делаем:
SELECT *, (SELECT COUNT(*) AS cnt FROM post_cnt c WHERE c.id = p.id) AS open_add
FROM posts p WHERE id=%id%
Единственное _но_ в бизнес логике страниц пришлось делать что-то типа:
$post = GetPostID( $id );
// После проверки, что с $post все нормально делаем:
$post['open'] += $post['open_add'];
И регулярно (раз в несколько часов) делаю:
set @n=subtime(now(),'01:00:00');
UPDATE posts p
SET p.open=p.open+(SELECT COUNT(*) AS cnt FROM posts_cnt c WHERE c.id=p.id AND dtime<=@n )
WHERE p.id IN (select pc.id from post_cnt pc WHERE dtime<=@n);
DELETE FROM post_cnt;
В Вашем случае можно написать
INSERT INTO user_la( lastactivity, id, dtime) VALUES (1226505039,1,now());
Вместо SELECT-а:
SELECT *, (SELECT MAX(lastactivity) AS la FROM user_la l WHERE l.id = u.id) AS user_lastactivity
FROM user u WHERE id=%id%
в бизнес-логике
$user['lastactivity']=$user['user_lastactivity'];
Ну и переодически можно делать:
set @n=subtime(now(),'01:00:00');
UPDATE user u
SET u.lastactivity=(SELECT MAX(lastactivity) AS ula FROM user_la l WHERE l.id=u.id AND dtime<=@n )
WHERE u.id IN (select la.id from user_la la WHERE dtime<=@n);
DELETE FROM post_cnt;
Хотя конечно с memcache получается в чем-то красивее
DELETE FROM post_cnt;
Лучше использовать TRUNCATE — он гораздо быстрее чем DELETE. TRUNCATE удаляет и воссоздает таблицу, что намного быстрее, чем поочередное удаление строк (при DELETE).
TRUNCATE post_cnt;
Думаю вы неправильно диагностировали медленный запрос. В таких случаях нужно смотреть не общее время, а lock time. Табличка эта очень мелкая, скорее всего у вас тормозит другой запрос с join с этой табличкой, поэтому накладывается блокировка чтения на user.
В похожей ситуации я тоже перевел user на inndb и LOW_PRORITY.
Не сказать что сильно помогло.
Медленный UPDATE vBulletin — в чем подвох?