Приветствую, есть 2 таблицы по 1 миллиону записей, запрос вида: Код (Text): SELECT COUNT(*) FROM products p LEFT JOIN product_descriptions pd ON p.product_id = pd.product_id WHERE pd.description != '' Запрос занимает 5с Возможно ли его как-то оптимизировать или нужно денормализацию делать?
а с WHERE pd.id IS NOT NULL не будет быстрее? в общем случае, я бы при таких раскладах действительно попробовал завести счётчики как дополнительные поля чтобы пореже вызывать COUNT(*)
индексы стоят на product_id в обеих таблицах. Я просто достаю инфу о кол-ве товаров, а так храню в редис кол-во, но приходится обновлять данные в кеше частенько
Как будто на допросе блин, долго ты эту информацию собирался хранить? я сам не читал что тут, держи изучай http://allyouneedisbackend.com/blog/2017/09/24/the-sql-i-love-part-1-scanning-large-table/
Про индексы... Здесь пересечение двух таблиц по миллиону. Если бы в product_descriptions не использовался индекс, то запрос выполнялся бы много много часов (миллион миллионов строк). А сколько именно - посчитай, или проверь. Потом расскажешь. ТС-у... Денормализация не обязательно, а вот кеширование подобных запросов на нужное тебе время самое оно.
Ну я к тому что, не он первый кому надо сделать пагинацию. Явно есть решение, и скрывать зачем ему столько строк было не к чему.
Спасибо почитаю. Вообщем есть парсер который парсит товары вот после идет сброс кеша по ключу и это происходит каждые 8 часов или когда в админке удаляют товар. Так же я храню в кеше кол-во товаров в зависимости от фильтра который применили например отобразить все товары без категорий тут уже другое кол-во --- Добавлено --- Да вот кеширую запросы и просто храню число для каждого запроса
>> Да вот кеширую запросы и просто храню число для каждого запроса Тогда твой вопрос не понятен. Ты хочешь избавиться от кеша для этих запросов?
Кешируй не средствами MySQL. Тем более, в 8-ке они нагло его выкинули. Хотя тебе подойдёт самый простой вариант (без Memcashed и т.п.), - создай sql-табличку с тремя полями и пользуй её в качестве кеша. До 1000 запросов в секунду хватит, даже больше.
Если знать количество строк необязательно, можно отказаться от COUNT и попробовать сделать пагинацию не в нумерованном виде 1 2 3 4, а кнопкой Далее. Допустим на страницу выводится 10 строк, запрашиваешь из базы 11 строк, дальше уже проверяешь, если в результате строк 11, показываешь кнопку Далее. И так с каждой страницей.
Возможно, только скорее всего бессмысленно. 10-50мс, которые не будут казаться тормозом на фронте ты не добьешься, потому всё равно придется так или иначе кэшировать. Если это метрика - просто посчитай и сохрани, для пагинации уходи в сторону предложения @qdevelopment с шагом через where id > X LIMIT Y (без offset). Ну а так, индексы по всем реально используемым в запросе полям, explain в попытках добиться того, что бы индексы применились, уменьшение полей используемых в запросе (т.е. не select *), возможно добавления оперативки планировщику, специфичные СУБД-фичи (типы индексов, какие-нибудь хитрые варианты запроса и т.п.) и местами денормализацию типа is_description_empty = true / false могут добить запрос до 200-400мс. Попробуй, такие заморочки как минимум полезны для наращивания скилла )