Pull to refresh

Comments 40

очевидно проблема не в этом запросе ;) просто когда он выполняется параллельно выполняется что-то более ресурсоемкое. почти готов поспорить :)
Раз 100 запускал /?explain=1 с рассмотрением запросов. Все чисто. Когда этот запрос не буксует, все грузится в за 0.1-0.2 секунды.
А когда буксует, то это же время + время пробуксовки.
Ну тогда предлагаю вам юзать UPDATE DELAYED, больше вариантов простых не вижу =)
можно понимать что Repair и Optimize были испробованы и не помогли, так?
Разница вот она 120000 против 20000, и неважно сколько пользователей онлайн, просто таблица больше. Все упирается в БД а не в движок. Можно поставить модификатор отложеного запроса LOW_PRIORITY, если это MySQL, но может поможет…
такое бывает… может стоит поменять тип таблицы например на InnoDB они не блокируют всю таблицу при вставке. И еще параметры сервера стоит подкрутить, чтобы больше памяти было у БД.
Памяти достаточно — по шаблону my-huge.cnf.
Перевел в 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 есть темы с форумами-миллионниками. Там есть много ответов и решений
Memcached включен, но он не касается вопросов записи в базу. Ключ есть по userid.
В том-то и прикол, что неясно откуда баг.
Какой движок у MySQL для базы используется? Не MyISAM случаем?
Поздравляю вы попали. Вы в курсе что при каждой операции записи лочится вся таблица? Просто потому что MyISAM не знает что такое транзакции. Если проблема именно в этом запросе то достаточно будет конвертнуть в InnoDB таблицу user и станет хорошо.

PS Вообще общий совет. Если у вас нет полнотекстового поиска в базе и много одновременных операций записи перейти на InnoDB. Правда предварительно подтюнив. Что тюнить и как можно посмотреть на MySQL Performance Blog. Ну и если все же MySQL не справляется рекомендуется мигрировать на PostgreSQL. Он лучше держит нагрузки и проще в обслуживании.
VBulletin, на сколько я помню, не знает, что такое транзакции.
А причем тут VBulletin? Главное чтобы СУБД знало. В случае если транзакциями не управляют явно, ими управляет СУБД и каждый запрос обрабатывается в пределах одной транзакции. Это так называемый autocommit.
Я бы скорее сказал, дело не в транзакционности, а в том, что MYISAM при записи лочит всю таблицу, а InnoDB — только ту строку, с которой работает.
Вообще-то InnoDB может лочить одну строку именно из-за механизма транзакций. В MyISAM он отсутствует по этому требуется блокировать всю таблицу если требутеся избежать проблем с целостностью данных.
а что статистика по поводу Locks говорит?
Ну а смысл от нее? Есть более простой и быстрый способ избавится от проблемы.
смысл увидеть… если во время проблемы будет куча Table locks waited то тогда да, а если не будет? ;)
Перевел в InnoDB — та же беда :-(
Page generated in 14.14102 seconds with 12 queries.
вы там ACID отключили? А то с ACID оно медленно работает. Ну и еще вопрос. Сейчас стабильно время на той query такое или нет?
Хм… У инноДБ отдельные параметры настройки…
Пиши в memcache, %username%
При низкой нагрузки — массовый update.

А вообще, пиши мне в личку — я могу пошаманить над innodb, часто помогает
А нефиг писать в таблицу, откуда постоянно ведутся выборки.
Такие «статистические» поля, которые часто обновляются, надо выносить в отдельную таблицу.
Решал схожую проблему, то есть у меня была конструкция вида:

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;
С опозданием… добавь LIMIT 1, но если и это не поможет попробуй отменить использование индекса т.е. делать полное сканирование таблицы.
Думаю вы неправильно диагностировали медленный запрос. В таких случаях нужно смотреть не общее время, а lock time. Табличка эта очень мелкая, скорее всего у вас тормозит другой запрос с join с этой табличкой, поэтому накладывается блокировка чтения на user.

В похожей ситуации я тоже перевел user на inndb и LOW_PRORITY.
Не сказать что сильно помогло.
Sign up to leave a comment.

Articles