如何提高mysql查询的查询速度

时间:2019-05-22 20:27:00

标签: mysql sql performance indexing

我正在尝试尽可能优化查询速度。另一个问题是我看不到确切的查询速度,因为它四舍五入到一秒。该查询确实获得了预期的结果,大约需要1秒钟。最终查询应进一步扩展,因此,我正在尝试对其进行改进。如何改善此查询?

该数据库被构建为电力公司。该查询最终应计算发票。我基本上有4个表,APX价格,powerdeals,powerload,eans_power。

APX价格是每小时价格,powerload是每季度小时数量。第一步是在每个刻钟中将这两个部分结合在一起。

第二步是,我当前选择表eans_power中指示的EAN。

最后,我将加入当前仅由一行组成的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 

权力交易

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 

powerload

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,日期,起始日期,有效期,价格
  • 1,2016-01-01,00:00:00,01:00:00,23.86
  • 2,2016-01-01,01:00:00,02:00:00,22.39

权力交易

  • 交易ID,日期交易,开始日期,结束日期,工作日起,工作日起至,期间起,期间至起,小时量,价格,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_id,ean,日期,起始时间,有效期
  • 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

  • ean,contract_id,invoicing_id,街道,号码,词缀,邮政,城市
  • 871688520000xxxxxx,1,1,road,14,postal,city
  

结果,不包含sum()并按以下项分组:

  • DATE,PERIOD_FROM,PRICE,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
  

结果,包含sum()和分组依据:

  • 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 个答案:

答案 0 :(得分:2)

初步优化:

  • 使用InnoDB,而不是MyISAM。
  • 仅将CHAR用于恒定长度的字符串
  • 使用一致的数据类型(例如,参见ean

要使用第二秒的方法,请查看Handler counts

因为范围测试(例如l.PERIOD_FROM >= a.PERIOD_FROM AND l.PERIOD_FROM < a.PERIOD_UNTIL)基本上是无法优化的,所以我建议您将表格扩展为每小时具有一个条目(如果需要的话,则为每季度1个)。通过键查找行比扫描“ ALL”表要快得多。整整一年的9K行是微不足道的。

当您跳过这些建议(和注释)时,我将获得有关优化索引的更多技巧,尤其是InnoDB的PRIMARY KEY