Большое разбиение таблицы истории продукта MySQL?

Я разрабатываю систему управления складом, написанную на php, laravel framework, mariadb. Чтобы получить всю информацию о каждом продукте, мы используем таблицу «история» продуктов, в которой регистрируются все действия, предпринятые с определенным продуктом. Эта таблица начала очень быстро расширяться, и теперь у нас есть ~ 15 миллионов строк в таблице innoDB, которая начала работать медленно, особенно при запуске функции, которая требует полного анализа того, сколько продуктов было продано, создано, выброшено и т. д., Тогда это занимает все 15 миллионов строк по одному запросу .. Итак, я начал искать способы, как работать с этой большой таблицей, потому что индексация больше не работает. Я начинаю думать о разделении / разбиении этой таблицы по дате, может быть, действие? Так что, может быть, у кого-нибудь есть опыт в этом и он может поделиться со мной советом? большое спасибо за любую помощь!

Большое разбиение таблицы истории продукта MySQL?CREATE TABLE `history` ( `id` int(11) NOT NULL AUTO_INCREMENT, `barcode` varchar(100) DEFAULT NULL, `bag` varchar(100) DEFAULT NULL, `action` int(10) unsigned DEFAULT NULL, `place` int(10) unsigned DEFAULT NULL, `price` decimal(10,2) DEFAULT NULL, `old_price` decimal(10,2) DEFAULT NULL, `user` int(11) DEFAULT NULL, `amount` int(10) DEFAULT NULL, `rotation` int(10) unsigned DEFAULT NULL, `discount` decimal(10,2) DEFAULT NULL, `discount_type` tinyint(2) unsigned DEFAULT NULL, `original` int(10) unsigned DEFAULT NULL, `was_in_shop` int(10) unsigned DEFAULT NULL, `cate` int(10) unsigned DEFAULT NULL COMMENT 'grupe', `sub_cate` int(10) unsigned DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, `helper` varchar(255) DEFAULT NULL, `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, `deleted_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `barcode` (`barcode`), KEY `action` (`action`), KEY `original` (`original`), KEY `created_at` (`created_at`), KEY `bag` (`bag`) ) ENGINE=InnoDB AUTO_INCREMENT=16274267 DEFAULT CHARSET=utf8

например запрос:

select  cate,
SUM(amount) AS amount, SUM(IF(discount>0,(price*amount)-discount,
                    (price*amount))) AS sum, SUM(IF(discount>0,IF(discount_type=1,
                                            (discount*price)/100,discount),0)
   ) AS discount from  history
    where  (history.action = '4'
              and  history.created_at >= '2017-11-01 00:00:00'
              and  history.created_at <= '2017-11-23 23:59:59'
           )
      and  LENGTH(barcode) > 7
      and  history.deleted_at is null
    group by  cate

этот запрос используется для получения информации о количестве, сумме, скидке о проданных продуктах (действие 4), в этом примере это информация между 2017-11-01 и 2017-11-23, и EXPLAIN дает мне это:

id - 1 select_type - SIMPLE table - history type - ref possible_keys - action,created_at key - action key_len - 5 ref - const rows - 1444272 Extra - Using where; Using temporary; Using filesort

поэтому требуется 1,5 миллиона строк с таблицей, в которой хранятся данные с 01.01.2017 г. по настоящее время, поэтому через 2 года потребуется 3 миллиона строк и т. д., когда мне нужно взять только информацию о проданных товарах за 2017-11 гг. И у меня есть еще много запросов, похожих на этот.

Что вы имеете в виду под «индексацией больше не работает»?

Nico Haase 03.04.2018 15:44

У меня уже есть 5 индексов (таблица справа на прикрепленном изображении), добавление дополнительных индексов больше не ускоряет работу.

Tomas 03.04.2018 15:49

Поддерживает ли EXPLAIN ваши медленные запросы эту гипотезу?

Nico Haase 03.04.2018 15:52

Скриншоты здесь практически бесполезны. Пожалуйста, используйте SHOW CREATE TABLE, чтобы описать вашу ситуацию и показать связанные с этим вопросы.

tadman 03.04.2018 21:37

обновлен основной вопрос с дополнительной информацией

Tomas 05.04.2018 09:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
5
229
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  • Используйте меньшие типы данных (уменьшение размера таблицы помогает повысить производительность) INT занимает 4 байта; доступны другие размеры.
  • PARTITIONing действительно обеспечивает любую производительность нет.
  • history.deleted_at is null - подумайте об удалении строк.
  • Узнайте о «составных» индексах, таких как INDEX(action, created_at). (Одновременно используется только один индекс.)

Большое улучшение происходит за счет создания и поддержки сводных таблиц; см. http://mysql.rjweb.org/doc.php/summarytables. Затем запустите запросы против них. И большинство индексов можно уйти.

Исправьте некоторые из них; тогда я могу вам помочь.

Более

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

  • INSERT INTO Fact и сразу же используйте IODKU для вставки или обновления сводной таблицы.
  • Выполните суммирование «по запросу» - когда пользователь запрашивает данные, сначала запустите INSERT .. SELECT .., чтобы захватить еще не суммированные строки и поместить подсчеты / промежуточные итоги в сводную таблицу.

Последний вариант работает, но есть две вещи, на которые следует обратить внимание:

  • Если в течение длительного времени ни один пользователь не приходит, обобщение может оказаться дорогостоящим. Простое решение - также периодически «догонять» работу cron. Убедитесь, что код заблокирован, чтобы cron и пользователь не обновляли одни и те же строки одновременно.
  • Если в сводной таблице есть «естественный» PRIMARY KEY, такой как дата (день или час) и несколько значений измерения, то у вас проблемы с INSERT. Либо избегайте этого в качестве PK (что приводит к множеству строк, что неплохо), либо используйте IODKU в форме INSERT ... ON DUPLICATE KEY ... SELECT ... GROUP BY ...; и используйте функцию VALUES(xx).

Я читал о сводных таблицах. Из этой статьи я понял, что мне нужно ВСТАВИТЬ ... ВЫБРАТЬ из истории в сводную таблицу. Но в моем случае мне нужны отчеты «с точностью до секунды», потому что все статистические отчеты являются «живыми», поэтому рекомендуется тип «по мере необходимости». Итак, я хочу спросить, лучше ли вставлять / обновлять сводную таблицу из таблицы «история» каждый раз, когда я обновляю страницу, а затем выбираю всю информацию из этой новой сводной таблицы, чем просто выбирать эту информацию из таблицы «история» напрямую? или, может быть, есть другой способ сделать это?

Tomas 27.06.2018 13:08

@Tomas - Я дам еще несколько советов.

Rick James 27.06.2018 22:49

Другие вопросы по теме