【问题标题】:How to improve query speed in mysql query如何提高mysql查询中的查询速度
【发布时间】:2019-10-09 09:30:45
【问题描述】:

我正在尝试尽可能优化我的查询速度。一个附带问题是我看不到确切的查询速度,因为它被四舍五入到一秒。查询确实得到了预期的结果,大约需要 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   

创建表查询:

价格

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 

电源负载

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,date,period_from,period_until,price
  • 1,2016-01-01,00:00:00,01:00:00,23.86
  • 2,2016-01-01,01:00:00,02:00:00,22.39

权力交易

  • deal_id,date_deal,start_date,end_date,weekday_from,weekday_until,period_from,period_until,hourly_volume,price,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,date,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

  • 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 秒。这个查询可以改进吗?” 我非常怀疑它是否返回了正确的结果(如果它确实是纯粹的运气)因为那不是你应该使用GROUP BY
  • 由于您的查询基本上是错误的,我建议Why should I provide an MCVE for what seems to me to be a very simple SQL query? 提供示例数据和预期结果..
  • 一个建议是将日期和时间存储为单个实体
  • 在开始优化之前,请修复GROUP BY。请注意,SELECT 正在获取(显然)取决于小时的列(例如价格)。
  • 似乎有 1 份合同。会有多个合同吗?他们会在特定的日子结束吗?中午换什么?另外如何切换到/从夏令时?

标签: mysql sql performance indexing


【解决方案1】:

初步优化:

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

有关使用秒级的替代方法,请查看Handler counts

因为范围测试(例如l.PERIOD_FROM &gt;= a.PERIOD_FROM AND l.PERIOD_FROM &lt; a.PERIOD_UNTIL)基本上不可能优化,我建议您将表扩展为每小时有一个条目(或每刻钟1 个,如有必要)。通过键查找一行比扫描“ALL”表快得多。一整年的 9K 行是微不足道的。

当您通过这些建议(和评论)时,我会有更多关于优化索引的提示,尤其是 InnoDB 的 PRIMARY KEY

【讨论】:

  • 谢谢,我会看看 InnoDB。谢谢,我将开始为固定长度的字符串和一致的数据类型使用更多的 CHAR。我会调查处理程序的数量。
  • 问题是每笔交易都是独一无二的,可能有不同的开始/结束时间/日期,并且可能仅适用于某个工作日。如果我应用这条规则,那么一笔交易基本上需要 365 天 * 48 个时间段,我不确定这是否是可行的方法。
  • 你怎么看?
  • @Introductiontoprogramming - 1 天交易可能需要与 1 年交易不同的查询。我希望需要在应用程序中做一些代码来帮助优化。 (或者使用杂乱无章的存储过程。)我的直觉(根据多年的经验)说你有一个相当复杂的问题需要优化。
  • @Introductiontoprogramming - 我对这个概念很感兴趣,并预测有一天电力公司可能会达到一分钟的粒度(不仅仅是 15m)。它将在我们的自动驾驶电动汽车内部进行计算,作为充电的优化。还有我们的冰箱,在决定何时运行压缩机。
猜你喜欢
  • 1970-01-01
  • 2021-11-17
  • 2012-03-31
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多