Производительность SQL-запросов на больших сайтах
Продолжение к этой статье: https://modxclub.ru/topics/tegi-dlya-krupnogo-sajta-2595.html (вынес и расширил комментарий). Информация по поводу производительности SQL-запросов на больших сайтах. На самом деле чаще всего основная нагрузка происходит в мало кому заметный момент - подсчет количества записей. Вот пример (это не документы, а заявки в CRM-системе, но для примера все равно сгодится, так как на документах и всем остальном все сказанное так же будет справедливо): Так вот, даже после оптимизации страницы, настройке вторичных ключей и т.п., всего при одном джоине со связью один-к-одному, выборка с подсчетом строк занимает несколько секунд. Даже оптимизировав getdata-процессор и исключив один запрос из трех, я все равно получаю довольно нерадостный результат. А вот если я исключу и запрос подсчета количества записей, то результат уже вот такой: Заметьте, что это еще с учетом выполнения консоли, обработкой данных на уровне PHP и т.п. То есть реально запрос выполняется где-то в районе 0.0003 сек. Такое поведение связано с тем, что при подсчете строк, если результат базе данных заведомо не известен (к примеру, при джоинах и условиях, когда базе приходится именно читать данные, а не просто "подсмотреть" в индексы), базе приходится читать все запрошенные таблицы целиком, а это самая медленная операция (ибо работа с диском). В таких случаях приходится думать об оптимизации всего приложения, чтобы запрос количества строк выполнялся только тогда, когда это реально нужно, а не каждый раз. Кстати, в MODX-процессорах (которые и getdata-процессор наследует), изначально было два полезных метода: prepareQueryBeforeCount() и prepareQueryAfterCount(). В getdata-процессорах изначально был добавлен еще один метод - setSelection(). Хотя он, по сути, дополняет метод prepareQueryAfterCount() и вполне можно обойтись без него, все-таки он по названию как-то боле логичный и традиционно использовался для добавления select-конструкций в основной запрос. Сейчас объясню логику. Вот возьмем, к примеру, основную таблицу документов. Когда вы просто формируете запрос из одной только его таблицы, даже если вы добавили какие-нибудь условия выборки, если на эти колонки созданы корректные индексы и БД использовала их для запроса, при подсчете количества записей скорее всего реального обращения к диску не будет, то есть кол-во строк БД подсчитает из индексов. В таком случае запрос на подсчет пройдет мгновенно. (Это область действия в рамках методе prepareQueryBeforeCount() и выполняемого за ним запроса на подсчет строк). А вот если вам надо получить данные из дополнительных таблиц (с использованием join-ов), то лучше их добавить уже в методе prepareQueryAfterCount() (или в случае использования getdata-процессоров в метод setSelection(), просто для наглядности). Вот тогда даже при использовании джоинов, запросы пройдут быстрее, так как не будет в этот момент выполняться подсчета строк.