Как улучшить скорость запроса в MySQL запросе - PullRequest
1 голос
/ 22 мая 2019

Я пытаюсь максимально оптимизировать скорость запросов. Побочной проблемой является то, что я не вижу точную скорость запроса, потому что она округляется до целой секунды. Запрос действительно получает ожидаемый результат и занимает около 1 секунды. Последний запрос должен быть расширен еще больше, и по этой причине я пытаюсь его улучшить. Как можно улучшить этот запрос?

База данных построена как электросетевая компания. Запрос должен в конечном итоге рассчитать счет. У меня в основном 4 таблицы, цена APX, powerdeals, powerload, eans_power.

Цена APX - почасовая, мощность - ежеквартальный объем. Первым шагом является объединение этих двух вместе на каждую четверть часа.

Второй шаг - я выбираю EAN, указанный в таблице eans_power.

Наконец, я присоединюсь к Powerdeals, который в настоящее время состоит только из одной строки и указывает, с какого часа, до какого часа и дня недели с / до он должен применяться. Он состоит из почасового объема и цены. В настоящее время он включается только в часы, но он будет распространен и на будни.

MYSQL-запрос:

SELECT l.DATE, l.PERIOD_FROM, a.PRICE, l.POWERLOAD, 
SUM(a.PRICE*l.POWERLOAD), SUM(d.hourly_volume/4) 
FROM timeseries.powerload l 
INNER JOIN timeseries.apxprice a ON l.DATE = a.DATE 
INNER JOIN contracts.eans_power c ON  l.ean = c.ean 
LEFT OUTER JOIN timeseries.powerdeals d ON d.period_from <= l.period_from 
AND d.period_until >= l.period_until 
WHERE l.PERIOD_FROM >= a.PERIOD_FROM 
AND l.PERIOD_FROM < a.PERIOD_UNTIL 
AND l.DATE >= '2018-01-01' 
AND l.DATE <= '2018-12-31' 
GROUP BY l.date

Объясните:

1   SIMPLE  c   NULL    system  PRIMARY,ean NULL    NULL    NULL    1   100.00  Using temporary; Using filesort 

1   SIMPLE  l   NULL    ref EAN EAN 21  const   35481   11.11   Using index condition

1   SIMPLE  d   NULL    ALL NULL    NULL    NULL    NULL    1   100.00  Using where; Using join buffer (Block Nested Loop)

1   SIMPLE  a   NULL    ref DATE    DATE    4   timeseries.l.date   24  11.11   Using index condition   

Создание запросов к таблице:

apxprice

CREATE TABLE `apxprice` (
  `apx_id` int(11) NOT NULL AUTO_INCREMENT,
  `date` date DEFAULT NULL,
  `period_from` time DEFAULT NULL,
  `period_until` time DEFAULT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`apx_id`),
  KEY `DATE` (`date`,`period_from`,`period_until`)
) ENGINE=MyISAM AUTO_INCREMENT=29664 DEFAULT CHARSET=latin1 

powerdeals

CREATE TABLE `powerdeals` (
  `deal_id` int(11) NOT NULL AUTO_INCREMENT,
  `date_deal` date NOT NULL,
  `start_date` date NOT NULL,
  `end_date` date NOT NULL,
  `weekday_from` int(11) NOT NULL,
  `weekday_until` int(11) NOT NULL,
  `period_from` time NOT NULL,
  `period_until` time NOT NULL,
  `hourly_volume` int(11) NOT NULL,
  `price` int(11) NOT NULL,
  `type_deal_id` int(11) NOT NULL,
  `contract_id` int(11) NOT NULL,
  PRIMARY KEY (`deal_id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 

мощность

CREATE TABLE `powerload` (
  `powerload_id` int(11) NOT NULL AUTO_INCREMENT,
  `ean` varchar(18) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `period_from` time DEFAULT NULL,
  `period_until` time DEFAULT NULL,
  `powerload` int(11) DEFAULT NULL,
  PRIMARY KEY (`powerload_id`),
  KEY `EAN` (`ean`,`date`,`period_from`,`period_until`)
) ENGINE=MyISAM AUTO_INCREMENT=61039 DEFAULT CHARSET=latin1 

eans_power

CREATE TABLE `eans_power` (
  `ean` char(19) NOT NULL,
  `contract_id` int(11) NOT NULL,
  `invoicing_id` int(11) NOT NULL,
  `street` varchar(255) NOT NULL,
  `number` int(11) NOT NULL,
  `affix` char(11) NOT NULL,
  `postal` char(6) NOT NULL,
  `city` varchar(255) NOT NULL,
  PRIMARY KEY (`ean`),
  KEY `ean` (`ean`,`contract_id`,`invoicing_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Примеры таблиц данных

apx_prices

  • apx_id, дата, period_from, period_until, цена
  • 1,2016-01-01,00: 00: 00,01: 00: 00,23.86
  • 2,2016-01-01,01: 00: 00,02: 00: 00,22.39

powerdeals

  • deal_id, date_deal, start_date, end_date, weekday_from, weekday_until, period_from, period_until, hourly_volume, цена, type_deal_id, contract_id
  • 1,2019-05-15,2018-01-01,2018-12-31,1,5,08: 00: 00,20: 00: 00,1000,50,3,1

powerload

  • powerload_id, ЕАН, дата, period_from, period_until, powerload
  • 1,871688520000xxxxxx, 2018-01-01,00: 00: 00,00: 15: 00,9
  • 2,871688520000xxxxxx, 2018-01-01,00: 15: 00,00: 30: 00,11

eans_power

  • ЕАН, contract_id, invoicing_id, улица, номер, наклеить, почтовый, город
  • 871688520000xxxxxx, 1,1, дорога, 14, почтовый, город

Результат без суммы () и группировка по:

  • ДАТА, PERIOD_FROM, цена, POWERLOAD, a.PRICE * l.POWERLOAD, d.hourly_volume / 4
  • 2018-01-01,00: 00: 00,27.20,9,244.80, NULL
  • 2018-01-01,00: 15: 00,27.20,11,299.20, NULL

Результат с суммой () и группировкой по:

  • DATE, PERIOD_FROM, PRICE, POWERLOAD, SUM (a.PRICE * l.POWERLOAD), SUM (d.hourly_volume / 4)
  • 2018-01-01,08: 00: 00,26.33,21,46193.84,12250.0000
  • 2018-01-02, 08: 00: 00,47.95,43,90623,98,12250,0000

1 Ответ

2 голосов
/ 23 мая 2019

Предварительные оптимизации:

  • Используйте InnoDB, а не MyISAM.
  • Используйте CHAR только для струн постоянной длины
  • Использовать согласованные типы данных (см., Например, ean)

В качестве альтернативы использованию времени до секунды, проверьте обработчик .

Поскольку тесты диапазона (такие как l.PERIOD_FROM >= a.PERIOD_FROM AND l.PERIOD_FROM < a.PERIOD_UNTIL) практически невозможно оптимизировать, я рекомендую вам расширить таблицу, чтобы иметь одну запись в час (или 1 на четверть часа, если необходимо). Поиск строки с помощью ключа намного быстрее , чем сканирование "ВСЕХ" таблицы. 9K рядов за весь год тривиально.

Когда вы ознакомитесь с этими рекомендациями (и комментариями), у меня будет больше советов по оптимизации индексов, особенно InnoDB PRIMARY KEY.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...