Pull to refresh

Comments 116

Часть советов вовсе не относится к оптимизации PHP:
— Объединяйте js и css файлы в один
— Используйте gzip

Сложные запросы можно спокойно строить без JOIN-ов (О, Боже! Этому надо учиться!)

«Не пытайтесь использовать короткие имена для классов и переменных»
— А кто-то использует короткие имена?
> — А кто-то использует короткие имена?
Я встречал людей, которые специально называли переменные $a, $b и т.п., чтобы код работал быстрее =)

> Часть советов вовсе не относится к оптимизации PHP:
Да, согласен. В статье со Сборником советов говорилось про статику, вот и решил упомянуть, как с ней лучше бороться.
Сейчас пых уже нормально относится к длинным именам, а в 3 ветке короткое имя переменной или класса обеспечивало прирост производительности, тем более на нагруженных сервисах. Своими глазами видел.
Да и плюс к этому сейчас существуют различные акселераторы. Просто мне сейчас со смехом вспоминается, что я когда-то заморачивался на длину названия переменной.
Новички — используют. Сам видел! :)
Вообще хорошая статья — есть что почерпнуть и новичкам, и средним разработчикам, и профи.
Вложенные select'ы могут быть эффективнее JOIN'в, но тут нужно немного мозг включать при их написании.
Не показатель, при большой выборке мускуль на 8 ядрах практически ложится. Хотя если аналогичные запросы делать через доп таблицы глотает на ура. Поэтому я бы не заявлял бы так громко что вложенные запросы это панацея от джойнов.
Не панацея, но я лично на своем примере видел как (!!!) 5 вложеных запросов работали быстрей одного лефт джоина в 25 раз, так что раз на раз не приходится, если давит можно и проверить =)
ИМХО это зависит от обьема базы и кол-ва элементов во вложенных запросах.
Часть советов вовсе не относится к оптимизации PHP:
— Объединяйте js и css файлы в один
— Используйте gzip

Статья и называется «По следам...»!
Наоборот, JOIN-ам учиться надо и далеко не очевидно
Крупные проекты вроде facebook, на сколько я помню, совсем отказались на боевых серверах от join'ов
да. я к тому и веду. что лучше всего работу разбивать на небольшие и быстрые запросы, с минимумом таблиц. В частности, изза поведения кешера, который при изменении одной таблицы сбрасывает кеш всех, то есть даже справочных которые не менялись.
Да, я об этом в посте и написал. Что намного проще кешировать небольшие независимые запросы.
«Не пытайтесь использовать короткие имена для классов и переменных»
— А кто-то использует короткие имена?

Здесь есть доля истины. Были статьи, даже с тестами, которые рекомендовали использование коротких имен для увеличения производительности. Эти статьи базировались для 4 ветки, как обстоят сейчас дела в 5 ветке лично я не скажу. Если интересен этот вопрос можете по гуглить и повторить тесты.
Доля истины есть. Только в итоге это вредит понимаю кода. А скорость, которую вы получите можно спокойно компенсировать включением кеша или какой-нить небольшой оптимизацией в коде.
Оптимизация это баланс между где то что то уменьшить, а где то добавить. Поэтому к задаче нужно подходить комплексно.
Да и в этот баланс еще входят трудозатраты на эту оптимизацию персоналом и последующая поддержка этого кода, что тоже крайне важно. Тут главное не перегнуть палку.
«Если возможно сделать расчет каких-нибудь данных на стороне PHP без ощутимых потерь во времени, то лучше сделать это
Масштабировать базу тяжело. Масштабировать бэк-энды намного проще.»

— Для нагруженных систем это не прокатит. Объясню на примере: Вам необходимо произвести расчет над данными в БД. Вы вытаскиваете данные из БД и делаете расчет в PHP. В это время кто-то меняет эти данные. И в результате Вы заносите в БД неверные данные.
В описанном вами случае действительно теряется достоверность данных. Я же говорил о случае, когда например надо вывести флаг «онлайн» пользователя. Сделать это можно дернув ключик в мемкеше при запросе из базы (ну или например сравнить с текущим временем), а можно дернуть этот же ключик при отрисовке пользователя в PHP на бэк-энде.
И это всё ради того, что бы не писать вычисления в SQL-запросах?
Да, потому что базу тяжело масштабировать. Есть и другой пример:
Если у меня в кеше лежит выборка первых 10-ти друзей пользователя, то для того чтобы вывести первых 3-х мне не надо делать запрос в базу. Я на стороне PHP могу сделать это, тем самым убрав лишнее обращение к БД.
А причем тут выборка? Мы говорили об изменении данных — кэш тут Вам не поможет.
Подсчет статистики лучше делать на стороне PHP или делать подсчет рейтинга пользователя/видео тоже лучше делать на стороне PHP, ведь в этом случае точность до секунды не важна, но база данных не будет загружена.
Тогда уточняйте свои слова в статье:
«Если возможно сделать расчет каких-нибудь данных, точность которых никому не нужна, на стороне PHP без ощутимых потерь во времени, то лучше сделать это»
вы сейчас занимаетесь «преждевременной оптимизацией» :)
Нет. Я рассказываю, как уже работает на боевых серверах. Конечно, когда писался код никто об этом не задумывался, но сейчас уже пришлось сделать такие изменения.
UFO just landed and posted this here
О дааа. Блокирующие транзакции такие блокирующие :)
Блокировка может быть и пессимистической. Другое дело, что выбор стратегии блокировки зависит от конкретной задачи.
Старайтесь под отдельный класс создавать отдельный файл
Да, у вас увеличится количество require (include, require_once, include_once), но зато найти определенный класс будет во много раз проще

Для того чтобы в проекте не было сотни инклудов, придумали функцию spl_autoload_register
Да, это тоже является одним из вариантов решения. Просто для меня нагляднее, когда все зависимости класса вынесены в заголовок файла.
В таком случае можно получить файлы с сотней инклудов, при том что 70 % зависимостей будут нужны только в одном из 10 методов класса, но подключаться все равно буду.
Грамотный автолоад рулит — файлы не теряются и подключаются только при необходимости.
Да, в этом случае можно делать require_once в том единственном методе, где он нужен, но ни к чему хорошему в итоге это все не приведет.

Вообще последнее время есть мысль попробовать объединить все файлы проекта в один большой и посмотреть, как поведет себя боевой сервер. Еще года два назад читал, что это вроде хороший способ повысить производительность, но руки так и не добрались.
Выигрыш будет за счет уменьшения дисковых операций в require (include, require_once, include_once).
Объединение в один файл покажет особо хороший прирост при использование акселераторов, например APC или упомянутый в статье eAccelerator.
Да, все верно. На то и надежда. Не попадались ли вам результаты таких тестов?
В статьях про фреймворк Yii на сколько помню были сравнения использования полной файловой системы и yiilite — как раз файла всё-во-одном. Сейчас не могу найти конкретного примера, а на форуме Yii устаревшие данные где собранный файл показывает не очень хорошие результаты.
Сейчас как раз делаю проект на yii. При высокой нагрузке толку от него немного — файлы и так в дисковом кэше.
Мы у себя на проекте так сделали — скинули 15мс. Что для нас неплохо — теперь генерация 8-10мс.
А какой размер итогового файла у вас получился?
Вы с ним еще что-нибудь хитрое сделали, вроде вырезания комментов, табуляций и т.п.?
Не, тупо bash скрипт собирает всегда нужные файлы в один.
Ага, это и было интересно. Но предыдущий вопрос в силе.
А у вас минимум кода для генерации страницы в мегабайтах ). Хоть 10кб, если они будут в 10 файлах это будет тормоз.
Я имел ввиду сколько получился в итоге файл, который объединил все файлы проекта.
Имелось ввиду: А у вас минимум кода для генерации страницы в мегабайтах )?
Для генерации страницы — минимум. Весь проект — 7 МБ кода, 700 файлов, и я не запариваюсь с их подключением или запоминанием где и что используется. Генерация от 30 мсек.
Пару лет назад Дмитрий Котеров делал тесты на Zend Framework (объединил все файлы в один), результаты здесь.
Почему-то так складывалось, что протестировать APC никак не хватало времени. Наверное стоит задуматься, чтобы сесть и попробовать.
UFO just landed and posted this here
думаю имелась ввиду его функция кеширования байт-кода
и чем же лучше APC?
на мой взгляд, единственный оптимизатор, которому можно доверять — это Zend Optimizer+ (не путать с похожим названием без плюсика в конце). быстрее всех существующих (APC, eAccelerator etc.) и надежен как скала, по той простой причине, что написан разработчиками PHP.
APC дефакто кешер начиная с версии 6.

по опыту работы с highload — ZendOptimizer — дрянь.
для 1 сервера — лучше APC в биде опкешера и кеша
для n серверов — eaccelerator для опкешера и memcached для кеша
вот я так и знал, что все забьют на плюсик в конце.

АЛОЭ!
ХАБРАХАБР!
ВНИМАТЕЛЬНЕЕ!

Zend Optimizer+ (Zend Optimizer Plus) — это другой оптимайзер, он входит в состав Zend Server/Zend Server CE, и немного быстрее, а, самое главное, в разы надежнее, чем eAccelerator. Скажем так, внедрение зендовского решения вообще незаметно с точки зрения совместимости, а вот с eAccelerator'ом возникают проблемы, — навскидку могу сказать, что modX требуется править в одном или даже нескольких глупых местах, чтобы не возникало ошибок.
Проясните мне пожалуйста один момент подробнее, ссылкой или фразой.

«Старайтесь кешировать все данные, которые приходят к вам из БД»

Я Smarty использую в разработке. Там есть кэширование сгенеренных страниц, т.е. оно как бы покрывает кэширование данных из БД.

Вы о каком кэшировании тут хотели сказать? Мне механизм нужен, просто хочу подумать над этим на досуге :)
Есть два пути кеширования: кеширование данных и кеширование результата.

Если кешировать данные, приходящие из выборки, то потом с ними можно делать что-угодно и выводить в любом удобном виде.

При кешировании результатов блоков шаблонов конечно возрастет скорость, но и возникнут дополнительные проблемы. Если об увеличение объема кешируемых данных можно и забыть, то про то, что один и тот же шаблон по разному выглядит для разных пользователей и зависит от большого количества внешних параметров не получится. К тому же у пользователя могут быть свои настройки (цвет интерфейса, язык, последние просмотренные клипы и т.п.).

В общем-то можно совмещать эти два способа, все зависит от контента на вашем сайте.
угу, значит надо изучать в сторону кэширование данных MySQL

Я механизм понять пока не могу. Это встроенные в БД средства какие-то или свой/сторонний велосипед?
Попробуйте почитать что-нибудь в сторону memcached
Про пхп практически ничего. Все изложенное в данном посте умещается в 3 строки
1) Пишите понятный код
2) Используете кэширование
3) Используется аккселераторы, nginx и сжимайте js/css

Причем к php относится только «Пишите понятный код». Спасибо КЭП
Как я уже говорил, я не пытался рассказать ничего нового, все это написано и не один раз. Если кому-то эта статья поможет сделать свой проект лучше и быстрее — это уже очень хорошо.
Прежде чем писать понятный код — требуется провести мозговой штурм и описать правила написания кода. По моему это самое сложное.
Лично я за основу взял Zend Framework Coding Standard for PHP с некоторыми незначительными изменениями.
— Используйте gzip
— Также очень хорошо использовать различные компрессоры, чтобы уменьшить объем этих файлов (Google Closure Tools, YUI Compressor и другие)

если вы используете gzip, компрессия скриптов особо ничего вашему серверу не даст…
Я говорил про то, что gzip'овать нужно js, css и html отдаваемый пользователю
И кстати компрессия на пару с gzip, хоть и незначительный, но дает прирост. Мелочь, а приятно.
Спасибо большое за советы, особенно какие технологии для чего использовать!
>> Если Хабрапользователь меня поддержит, с огромным удовольствием эта статья будет началом цикла статей по оптимизации.

Было бы очень интересно почитать цикл статей о построении архитектуры высокнонагруженных проектов.
Масштабирования уже запущенных проектов.
Да, тема интересная. Даже очень близкая =) Как раз сейчас занимаюсь поднятием и планированием такой архитектуры с нуля.
Хорошая статья, а не «print быстрее echo», «sizeof быстрее count». Экономия на спичках никогда не дает больший результат.
Очень убедительный материал по оптимизации (и все равно начинающие программисты, особенно олимпиадники, его не усваивают):

Оптимизация — Ваш злейший враг!.

Суть одной строкой: единственно верный подход к оптимизации — инженерный: Вы сначала измеряете (а не рассчитываете!) производительность с помощью инструментов (профайлеров), находя узкие места, а затем оптимизируете только их.

То есть пишите сначала максимально поддерживаемо (просто, красиво), а усложняйте оптимизацией только при необходимости.
Отличная статья, хоть и большая — нисколько не жаль потраченного времени
Почему в статьях о PHP не пишут про замыкания и неймспейсы (ну и Trait's)? Или ими никто не пользуется? Как они влияют на производительность?
Я пробовал. Если вы с ими хотите обрабатывать большой массив данных — то не стоит.
Да. У меня использование замыкания в одном месте при обработке массива элементов так в 50к тормозило прилично. На порядок замедлило чем в варианте без нее. Но не думаю что она сильно повлияет в простых случаях. Хотя ребята тут смотрели ее непосредственную реализацию, им не понравилось ).
год? да такие статьи каждые 3 дня появляются
На главную пролазят всегда две. Первая — кривая. Вторая — по мотивам первой с нравоучениями :)
UFO just landed and posted this here
От nginx, по-моему, польза видна при больших нагрузках.
У меня после установки nginx для отдачи статики, сайт быстрее работать не стал (при 1000 посетителях в сутки).
Или я что-то неправильно сделал?
Не понятно, как именно вы оцениваете «сайт не стал быстрее работать». Вы пробовали открывать свой сайт с отключенным кешем в браузере? Там разница не так ощутима, но когда у вас на морде около 500.000, тогда эти вещи становятся более ощутимы. В вашем случае это не должно быть так критично =)
У PHP проблема, что вряд ли кто-то будет использовать после вас ваш код :) проще его переписать уже к тому времени будет, чем оптимизировать кастылями, язык не приветствует рефакторинг как Java или Ruby
Рефакторинг != оптимизация. А то, какая архитектура будет у вашего кода зависит целиком от вас, программистов. На Java и Ruby можно тоже встретить код, который проще выкинуть, чем пытаться рефакторить.
Открою секрет — таки да :)

Применительно к Джаве — для того чтоб вывести «Привет мир» в одном проектике нужно собрать как мин. 5 внутренних либ. Или при пропатчивании глюка в одной перестает работать пол проекта которые вообще не относятся к этой либе. Это не прикол а реалии жизни. Такшо идеями ОПП можно не только упростить жизнь, а и омрачить.

ЗЫ. пословица: Чужой код — потемки.
То есть свой каждый проект вы начинаете с переписывания всего кода, который был до вас?
И причем тут джава и ООП, если просто вы столкнулись с какими-то кривыми костылями в коде, из-за которых проект рассыпается?
В моем посте было упоминание об новых проектах ;)
Какие паттерны рефакторинга нельзя применять в PHP, но можно в Ruby?
Знаете, с оптимизацией очень интересно. Сначала всё время слишком рано, а потом — раз и уже поздно.
Тут главное не упустить момент между «ну еще рано, у нас нет столько народу» и "***** мы лежим" =). Вообще оптимизацией надо заниматься тогда, когда сайт перестает справляться с нагрузкой и прооптимизировать быстрее, чем вводить новые сервера.
К примеру, для получения информации о пользователе в комментариях (при отрисовки ника) проще сделать отдельный запрос (конечно же закешировав его), чем JOIN на таблицу пользователей


Никогда этого не понимал, это если 20 комментариев я вывожу, я делаю еще 20 запросов?
Хотя наверное можно сначала выбрать 20 комментов, потом один запросом 20 юзеров. В пыхе все склеить и выдать результат.
Гуру хайлоада, поделитесь информацией.
Выбирается 20 комментариев, дальше для каждого комментария выбирается пользователь из кеша (а если нет в кеше, то делается SQL запрос и кладется в кеш).

Идея в том, что информация о пользователе выбирается не только на странице комментариев, но и на других страницах сайта, а значит скорее всего уже лежит в кеше и выбирать юзеров можно очень быстро.
Хорошо. Тогда посложнее задача.

2 таблицы

1я таблица — фотки
2я таблица — какой юзер за какую фотку голосовал

SELECT * FROM photos WHERE
photo_id NOT IN( SELECT photo_id FROM votes WHERE user_id = '$user_id' )

Как тут поступать?

Вариант сначала выбрать все ID за которые голосовал, а потом вставить во второй запрос айдишки через запятую — не подходит, т.к. юзер может оценить и 3к фоток, не будешь же 3к айдишек перечислять?
А объединить таблицы по ключу что мешает ;). Дальше уже по задаче сортировка/группировка и пр. можно это и на базу переложить можно и в коде.
Запрос сам по себе медленный. Вы только представьте, вы из всей таблицы фоток пытаетесь выбрать фотки, за которые пользователь не голосовал =)

Мне в голову не приходит, зачем это надо. Он в любом случае будет медленным.

В реальности ситуация как мне кажется может быть такой:
1. Это виджет в котором показывается рандомная фотка, за которую пользователь может проголосовать. Тут все просто выбираем 10-20-30 фоток за которые пользователь мог бы проголосовать и для каждой смотрим, было ли голосование или нет. Если было, то не показываем.
2. Если пользователь смотрит альбом фоток, то соответственно то же самое, смотрим за какие фотки пользователь голосовал, а за какие нет.

В любом случае у вас всегда должно быть какое-то ограничение на список выбираемых фоток.

Также не забывайте, что из мемкеша много вытаскивать ключи не по одному, а сразу списком, что ускоряет работу с ним.
Приложение, суть которого оценивать фотки других пользователей.
Все фотки показываются по очереди.
Нужно показывать только те фотки, которые пользователь не оценивал.
Таблица, в которой лежат оценки разрастается очень быстро. Уже более миллиона записей.
Соответственно ваши варианты не подходят.
Да, и чем более популярным будет становится — тем больше записей будет появляться как в таблице фоток, так и в таблице голосов.

Из вариантов оптимизации могу лишь предложить перед входом пользователя сразу подготавливать ему очередь фоток из 10-20-30, за которые он не голосовал и потом их постепенно ему отдавать. Сколько фоток за сессию отмечает пользователь вы из своей статистики должны знать. Такой вариант будет грузить базу, но намного реже.

Второй вариант — запоминать дату фотки, за которую пользователь голосовал в последний раз и в выдаче дальше выдавать ему только самые новые фотки. Тогда и выборка из базу станет проще намного и в таблицу голосов лазить не надо.

Третий вариант — это держать очередь «супер-новых» фоток, и отдавать пользователям фотки из этого списка. Такой вариант должен сработать, если у вас достаточно хорошая текучка фоток.
Второй и третий вариант отпадает, потому что при выводе фоток делает упор на фотках тех людей, которые больше всего голосовали.
Т.е. фотки активных людей выводятся чаще, чем неактивных.

Первый вариант интересный.
В случае с очередями теоретически их еще можно пытаться рассчитывать заранее, до того как придет пользователь, но в этом случае надо больше статистики и анализа, чтобы понять для кого и как их рассчитывать. Может быть рассчитав очереди для 20% активных пользователей ночью, когда народу мало, вы сможете разгрузить базу во время пиков, когда основной поток людей приходит к вам.
>При разнесении таблиц на различные сервера БД, запросы на JOIN вообще могут перестать работать
ну, если мы хотим, чтоб наша система была масштабированная, то от JOIN надо отказаться впринципе!
смотрим в сторону денормализации
Согласен с автором данного топика. То что он описывает, имеет большее отношение к крупным нагруженным проектам. Сам через это прошел и полностью согласен с автором.

Если продолжите делиться опытом — буду рад и с удовольствием читать и обсуждать!
Для отдачи статического содержимого используйте nginx или lighttpd

А как их лучше использовать. Варианты с ходу:
— nginx+php-fpm — nginx и статику отдаёт, и через fcgi скрипты вызывает
— nginx+Apache+mod_php — аналогично, но проксирует запросы к апачу
— nginx-прокси, nginx для статики, и nginx+php-fpm или Apache+mod_php
— nginx для статики на другом интерфейсе/хосте, nginx+php-fpm или Apache+mod_php для скриптов на основном.
БОЛЬШОЕ человеческое спасибо!
А то я уж кинулся "$var«ы вычленять, да точки на запятые менять )
Как-то так хорошо становится после таких статей, типа: „Правильной дорогой идете, товарищи!“
Sign up to leave a comment.

Articles