Все-таки решил написать этот небольшой обзор про пути решения существенной проблемы е107 - нагрузки на базу данных. Пусть это будет моим посильным вкладом в еще живую часть е107 сообщества
е107 пользуюсь с 2005 года, и все это время на различных сайтах переодически всплывают темы насколько этот движок неоптимизирован, как много у него делается ненужных запросов к базе и вообще при посещаемости больше тысячи человек в день он просто умирает.
На мой взгляд это не совсем так - работа с базой построена вполне нормально, и дальше я расскажу, как можно существенно уменьшить нагрузку на базу данных, не прилагая сверхъестественных усилий.
Все что я пишу основывается на семилетнем опыте владельца самого посещаемого сайта в России на движке е107 - в день стабильно 10-30 тыс пользователей, в среднем 1600000 просмотров в сутки. По-крайней мере большие мне неизвестны - филка имхо не в счет, у них е107 служит только для новостей, основная часть посещает только форум IPB и основная нагрузка на базу идет именно с него.
Для все еще сомневающихся скриншотик из phpmyadmin - поверьте, без подобной оптимизации дела были бы значительно хуже + Показать
Ну и наверное подобная оптимизация важна при посещаемости от 500 человек в день и выше. Если у вас в день ходит 50 человек и смотрит 1000 страниц, то морочится с какой-то там оптимизацией не стоит.
Итак, я использую 4 метода отпимизации работы с е107: 1) Индексы на таблицы 2) Оптимизация запросов в class2.php 3) кэширование результатов работы плагинов 4) оптимизация наиболее медленных запросов
1) Индексы на таблицы Это абсолютно понятная нормальная человеку вещь (вопрос конечно почему ее нет по-умолчанию в е107). Кому непонятно - Все нагруженные таблицы, то есть как минимум #comments, #news, #private_msg, #rate, #user, #user_extended должны быть с индексами к соответствующим полям int (кое-где и к varchar) Например, к таблице #comments у меня забито следующее: + Показать
PRIMARY - comment_id
INDEX - comment_type
INDEX - comment_item_id, comment_type
INDEX - comment_author(5)
INDEX - comment_datestamp
В общем индексов много не бывает (ну кроме как к совсем часто изменяемым полям), поэтому phpmyadmin в руки и вперед
2) Оптимизация запросов в class2.php Как некоторым здесь должно быть известно, class2.php инклюдится при обращении к любой странице движка e107 (ну кроме может быть rss, printnews и request), поэтому оптимизация запросов в нем сказывается сразу на всем сайте. Суть самой оптимизации просто - уменьшение количества избыточно выполняемых запросов. К примеру, на мой взгляд совершенно излишне при генерации каждой страницы очищать временные таблицы, удалять забаненных пользователей и тд. Кроме лишней нагрузки на базу толку от этого - ноль. Поэтому нужно немного модифицировать код class2.php таким образом, чтобы подобные запросы выполнялись к примеру 1 раз на 100 (1000, 10000) генераций страниц. Модификация кода простейшая - перед каждым запросом ставите if (rand(0, X) == 1) { код_запроса; } где X должен быть подобран эмпирически именно для вашего сайта. Напишу то что изменил лично я, но имхо это с оглядкой на разницу в посещаемости не лишне будет сделать каждому. + Показать
-if(rand(0,10000)==1){$sql->db_Delete("user","user_ban = 2 AND user_join < '{$threshold}' ");}
-if(rand(0,250)==1){$sql->db_Delete("tmp","tmp_time < '".(time()-300)."' AND tmp_ip!='data' AND tmp_ip!='submitted_link'");}
-if(rand(1,50)){$sql->db_Update("user","user_currentvisit = '{$result['user_currentvisit']}'{$update_ip} WHERE user_id='".USERID."' ");}
Кстати, каждый из этих четырех запросов может вызывать блокировки таблиц, что является еще одним поводом вызывать их пореже
3) кэширование результатов работы плагинов В е107 очень удобно добавлять различные статистические плагины в правую или левую часть сайта. Например, последние комменты, случайная картинка, последние закачки, кто онлайн и прочее. Многие злоупотребляют этим делом, в результате при генерации каждой страницы бедный движок трудолюбиво и вхолостую проводит очень много вычислений. Например, для получения 5 последних комментов ему нужно: 1) считать в память всю таблицу комментов 2) если требуется только комменты к например новостям, то отфильтровать ее 3) отсортировать получившиеся данные по времени (а скажем 50 тыс комментов даже при наличии индекса будут отсортированы не так уж и быстро) 4) взять 5 первых комментов
Самое смешное, что эти 5 комментов будут с очень большой вероятностью совпадать с теми, которые только что были сгенерированы для другого пользователя, да и вообще первый новый коммент появится через 3 часа Поэтому понятно, что вывод на главную только к примеру последних новостей, последних комментов, последних сообщений форума и последних закачек нагрузят базу данных по-полной абсолютно бессмысленной работой. Но допустим вам жизненно необходимо выводить всю эту информация на каждой странице каждому пользователю. Мне например необходимо, так как это и удобно, и функционально, и полезно. Что делать?
Выход очень прост - надо проводить все эти вычисления только один раз, результат записывать в базу, а затем в течение определенного времени (ну например вы считаете, что список последних комментов следует обновлять только каждые 10 минут) просто выводить пользователю. Можно подумать, что одно обращение к базе (к таблице комментов) просто заменяется обращением к таблице с хранимыми результатами. Это не так. В плагине может быть несколько сложных запросов (как показано выше - фильтрация, сортировка), в то время как вы меняете их на один простой (выборка). Более того, никто не мещает вам (я например даже рекомендую ) сделать эту выборку отдельно не в каждом плагине, а только один раз при генерации страницы. Тогда получится, что запросы _всех_ подобных плагинов (10, 20, ...) в общем случае будут выполняться за один-единственный select.
Теперь о том как это сделать. Все очень просто: 1) Создаем в базе данных таблицу #mycache
mycache_id - идентификатор плагина mycache_datetime - время последнего обновления данных данных mycache_title - заголовок данных mycache_description - сами закэшированные данные
2) В class2.php где-нибудь в середине добавляем: + Показать
//добавляем команду для переодической очистки кэша - а то че-то глючит время иногда...
3) В плагине который собрались отпимизировать надо "обернуть" весь исполняемый код вставками для анализа последнего обновления и для сохранения данных в базе. На примере - вот код плагина, выводящего список последних новостей: + Показать
<?php
$sql->db_Select_gen("select * from #news order by news_id desc limit 5");
4) оптимизация наиболее медленных запросов Это самый сложный путь, поэтому думаю именно вам он может уже и не понадобиться если вы проделали 1-2-3 Поэтому мне и лень уже его расписывать, кому надо, прочитайте про: 1) определение медленных запросов 2) их оптимизацию
В общем как-то вот так. Дураки я думаю до этого места уже не дочитают (если дочитали, не надо писать всякую дичь в комментах), а умные могут попробовать эти пути или описать своим методы