【发布时间】: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