Задать вопрос
librown
@librown
На-все-руки-мастер и немного кодер

Селекты из таблицы на 5 млн строк. Если разбить её на 100 таблиц — будет выигрыш в производительности?

Приветствую, коллеги!

Посоветуйте, есть таблица с товарами (InnoDB на 5 млн строк). Индексы добавлены. Но на сервере всего 4Гб памяти.

Приходится делать много запросов к ней с джойнами других больших таблиц (фильтр интернет-магазина: по производителю, цвету; сортировка по цене, по дате). Такие селекты выполняются иногда до 30 секунд.

Есть ли смысл раскидать товары на 50-100 таблиц (для каждой категории свою таблицу)? В итоге получатся таблицы по 30-100 тыс строк, не больше. Таким образом можно радикально улучшить производительность?

Или, все же самый правильный вариант - это добавить памяти гигабайт до 16 и наслаждаться результатом? :)

Спасибо!
  • Вопрос задан
  • 4863 просмотра
Подписаться 13 Оценить 3 комментария
Пригласить эксперта
Ответы на вопрос 14
ThunderCat
@ThunderCat Куратор тега MySQL
{PHP, MySql, HTML, JS, CSS} developer
Поддерживаю longclaps, вы что, алиекспресс админите? откуда в таблице товаров 5М строк, вы что, спички поштучно учитываете? Это номер раз, второе - если фильтры такие забубенные - делайте в 2-3 запроса через бэк, что у вас там, пых, нода, джанга, ограничивайте по уму количество товаров в первой выборке по самому быстрому индексу и самой ограничивающей выборке, например все товары выбранной категории, далее филтр только на результат выборки по типу id in(1,2,3,4). И все же скажите, не мучьте, ОТКУДА СТОЛЬКО ТОВАРОВ БЛИН, я ж не засну теперь...
Ответ написан
@laxikodeje
5 миллионов записей для современных СУБД - это ерунда.
Было бы 5 миллиардов - можно было бы так заморачиваться, как вы хотите.

Дело в том, что вы не правильно организовали хранение фильтров.
Это действительно простой метод, но SQL в нормализованной форме не подходит для фильтров товаров по категориям товаров и интернет-магазине.
Нужна или ДЕНОРМАЛИЗОВАННАЯ форма с дублированием.
Или вообще БД другого типа. Я лично под такую задачу фильтрации предпочитаю Tarantool, но, полагаю, годится и Solr

Или, все же самый правильный вариант - это добавить памяти гигабайт до 16 и наслаждаться результатом? :)


Не-а.
Не будет толка.
Кроме того не забывайте - современные требования таковы что было бы весьма хорошо если бы фильтр отрабатывал вообще мгновенно почти, пока пользователь поставил очередную галку - товар по предыдущему фильтру уже загрузился с сервера в браузер.
Ответ написан
longclaps
@longclaps
Что там делает таблица на 5млн строк? Отнести нахер в архивную таблицу всё, что 10 лет как мхом позарасло - это осмысленое действие. Уверен, 90% говна улетит по самым мягким критериям.
100 актуальных таблиц - это гораздо больший ад чем то, что есть.
Ответ написан
Комментировать
gobananas
@gobananas
finishhim.ru
Нет, выигрыша вы не получите, потому что в MySQL есть ещё время на открытие таблицы некоторое, и там доп. логику придётся писать с условиями из какой таблицы выбирать. Надо денормализовать данные хотя бы немного, сделать EXPLAIN, посмотреть, бывает MySQL сходит с ума и не использует правильные индексы.
5 млн. это не очень много, уверен всё можно привести в норму.
P.S. Сам работал с таблицей 3,5 млн. записей на сервере с 2 Гб памяти, всё отлично, дольше 0,1 секунды запросов нет, хотя и это многовато имхо.
Ответ написан
Комментировать
landergate
@landergate
IT-шный jack-of-all-trades
Прироста не будет.
Но давайте посмотрим на проблему под другим углом:

5кк строк - это ничтожное кол-во. Если у вас происходят селекты по 30 секунд, значит либо у вас не выставлены правильные индексы на те колонки, которые вы селектите, либо вы совершаете LIKE, начинающиеся с %. Индексы не используются при запросах LIKE %...%. Только при LIKE ...%

Ещё одна возможная причина - это хранилище. Посмотрите, не упирается ли всё в этот момент в диски. Если окажется, что в момент тяжёлых запросов у вас высокий iowait, попробуйте мигрировать на площадку с SSD.
Ответ написан
Комментировать
1. Возможно, тут более правильно использовать noSQL.
2. Даже если SQL (= РСУБД) - нужно избавляться от JOIN-ов.
Но! ! Уровень JOIN-ов =1 может оказаться вполне приемлем, если вы
- при фильтрации на фронте сразу выделите id связанных сущностей (бренд, цвет, и т.п.)
- правильно настроите индексы, и сделаете правильные запросы
Например, при хотя бы одном активном фильтре делаете 1 SELECT, а потому уже в PHP (или что там у вас) отфильтровываете по другим параметрам.
И да, надеюсь, тексты и тем более картинки (не в БД же они?) у вас не выбираются этим же запросом?
Если вдруг выбираются (типа SELECT * ..), замените "*" на "поле1, поле2" (только нужные), может оказаться приятным сюрпризом
Ответ написан
Astrohas
@Astrohas
Python/Django Developer
Но на сервере всего 4Гб памяти.

Тоже работал с АНАЛогичным сервером,и базой в 90гб!
Как вы будете иметь доступ к таблицам категорий? Обычно франкейнштейномеркеры делают вспомогательную таблицу типа "category - category_tabe_name". Но учтите что для изъятия любого товара из базы, придется делать минимум два запроса.
Также нужно учесть фильтры по нескольким категориям, и для например 2 категорий будут два запроса для запрашивания таблиц, и два для запрашивания информации из таблиц + еще один для результатирования.
Гораздо проще докупить памяти, поднастроит кешировоание, добавить дополнительные индексы и всякую всячину.
----
и если вы все еще хотите делить по таблицам советую использовать стандартные инструмены мускула вроде "partitioning" который особенно полезен, и на хабре есть мануальчик по этому https://habrahabr.ru/post/66151/
Ответ написан
chupasaurus
@chupasaurus
Сею рефлекторное, злое, временное
Clickhouse. Б-гоподобные индексы, column-based, вот это вот всё.
Ответ написан
Комментировать
@Mountaineer
Если вкратце, то у вас три варианта:
1. оптимизировать запрос
2. вертикальноє масштабирование БД (более мощный сервер)
3. горизонтальное масштабирование БД (шардинг)

То, что вы хотите - ето антипаттерн: https://stackoverflow.com/questions/16721772/mysql...
Ответ написан
Комментировать
dimonchik2013
@dimonchik2013
non progredi est regredi
память да, но для JOIN проц важнее, попрофилируйте лучше запросы
Ответ написан
Комментировать
al_gon
@al_gon
Приходится делать много запросов к ней с джойнами других больших таблиц (фильтр интернет-магазина: по производителю, цвету; сортировка по цене, по дате). Такие селекты выполняются иногда до 30 секунд.


SQL здесь не подходит.
Как реализуется набор фильтров для различных категорий по характеристикам товара?

Faceted Search with Solr
Ответ написан
Комментировать
@Fortop
Tech/Team lead
В такой постановке вопроса - самый правильный вариант оценить стоимость каждого из решений на некоторый срок (года, два, десять) зависящий от скорости изменений в проекте и его среде окружения.
И выбрать более эффективное с точки зрения стоимости.
Ответ написан
Комментировать
akzhan
@akzhan
Вам поможет такое эмпирическое правило - увеличение размеры таблицы в 10 раз замедляет поиск по индексу не более, чем вдвое. Увеличение таблицы в 100 раз уменьшает поиск не более, чем в 4 раза.

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

Что я вам рекомендовал бы - просто вычитать EXPLAIN.

Далее просто сменить MySQL на Postgres.

И только после этого заниматься denormalization, NoSQL etc.
Ответ написан
Комментировать
DimonSmart
@DimonSmart
Kaspersky Lab Developer
Самое важное в любой БД - это структурная оптимизация. Возможно стоит перепроектировать таблицу и посмотреть в сторону классической нормализации. Полностью согласен с теми, кто очень сомневается в номенклатуре в 5 млн. записей.
Классика - это одно наименование в основной таблице а цвета, размеры и т.п в другой. А в прайсе и складе - комбинации. Кстати, при классическом подходе у вас фильтры естественным образом сами разложаться на разные таблицы.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы