我正在开发专业的基于Web的服务,能够监控电能消耗或能源生产(即来自光伏或风能源)。该项目使用专有电子(由我开发)收集电气参数,如电压,电流和相角。多个JOIN的MySQL性能问题
- 远程设备将这些参数发送到Apache Web服务器脚本,该脚本将原始数据推送到托管在单独服务器上的MySQL数据库中。
- 每个远程设备都有自己的DEVICE_ID。
- 数据每30秒发送一次,因此有一天我们每个设备都有2880行。
虽然MySQL服务器的计算能力很强大,但Apache服务器不显示任何性能问题我无法在不到60秒的时间内执行查询。我使用了所有的工具(键和索引)并正确设计了查询(我希望),但我无法理解错误。我在DB设计方面的经验主要来自Oracle和SQL Server,我在MySQL上的经验非常有限(作为专业人员)。
服务器硬件:在Windows Server 2008上运行的2x Xeon CPU 64位+ 4GB RAM,是的MySQL安装在Windows2008上,因为它是我非常熟悉的平台。
该数据库是非常简单的:
表1:DATA_RAW由托管的电气参数几个字段,加上包含数据生,包含远程设备ID字段DEVICE_ID的时间戳的字段SRV_TIMESTAMP。
所有远程设备每30秒将数据推送到此表中。主键是一个集群:DEVICE_ID + SRV_TIMESTAMP与这些字段一样,不可能有来自同一设备的重复行。
该系统还接收气象数据,如温度,压力,湿度,云等。他们每小时发送一次。这些数据被推送到另一个名为WEATHER_DATA的表中,主键又是一个集群:DEVICE_ID + SRV_TIMESTAMP。唯一的区别是,我们每天在这里每个设备只有24行。
,其中包含有关于太阳辐射对每个设备信息命名SUN_DATA第三个表。这用于计算PV场效率。托管这些数据的表名为SUN_DATA,并包含各种字段,主密钥又是一个集群:DEVICE_ID + SRV_TIMESTAMP。
重要的是要注意的是,SRV_TIMESTAMP在所有设备之间同步,以便任何数据集将共享相同的时隙(每天提供2880个时隙中的一个)是很重要的。
这里从DATA_RAW表来的数据的一个示例:
SRV_TIMESTAMP | DEVICE_ID | VOLTAGE | CURRENT | PHASE
-----------------------------------------------------------
2014-08-21 22:23:30 | 0AF500100 | 243 | 5.4 | 0.01
2014-08-21 22:23:30 | 0AF456102 | 240 | 3.4 | 0.15
2014-08-21 22:23:30 | 0BFDE0010 | 239 | 2.4 | 0.65
2014-08-21 22:23:00 | 0AF500100 | 241 | 5.2 | 0.37
2014-08-21 22:23:00 | 0AF456102 | 239 | 3.4 | 0.12
2014-08-21 22:23:00 | 0BFDE0010 | 238 | 2.5 | 0.64
2014-08-21 22:22:30 | 0AF500100 | 240 | 5.4 | 0.02
2014-08-21 22:22:30 | 0AF456102 | 236 | 3.2 | 0.16
2014-08-21 22:22:30 | 0BFDE0010 | 239 | 2.0 | 0.67
这里从DATA_SUN表来的数据的一个示例:
SRV_TIMESTAMP | DEVICE_ID | SUNPOWER| SUNAZIMUTH
------------------------------------------------------
2014-08-21 22:23:30 | 0AF500100 | 845674 | 175.1
2014-08-21 22:23:30 | 0AF456102 | 866467 | 175.2
2014-08-21 22:23:30 | 0BFDE0010 | 867686 | 175.4
2014-08-21 22:23:00 | 0AF500100 | 867685 | 175.6
2014-08-21 22:23:00 | 0AF456102 | 867876 | 175.9
2014-08-21 22:23:00 | 0BFDE0010 | 867855 | 176.0
2014-08-21 22:22:30 | 0AF500100 | 867879 | 176.2
2014-08-21 22:22:30 | 0AF456102 | 856578 | 176.4
2014-08-21 22:22:30 | 0BFDE0010 | 876789 | 176.4
这里来自的数据的样本DATA_WEATHER表:
SRV_TIMESTAMP | DEVICE_ID | CLOUDS | TEMPERATURE
------------------------------------------------------
2014-08-21 22:00:00 | 0AF500100 | 30 | 36.1
2014-08-21 22:00:00 | 0AF456102 | 35 | 26.2
2014-08-21 22:00:00 | 0BFDE0010 | 34 | 35.4
2014-08-21 21:00:00 | 0AF500100 | 70 | 36.6
2014-08-21 21:00:00 | 0AF456102 | 10 | 26.9
2014-08-21 21:00:00 | 0BFDE0010 | 20 | 35.0
2014-08-21 20:00:00 | 0AF500100 | 30 | 32.2
2014-08-21 20:00:00 | 0AF456102 | 20 | 23.4
2014-08-21 20:00:00 | 0BFDE0010 | 65 | 34.4
请注意,对于仅天气,数据会在每个侯而对于其他表格数据每30秒推动一次。 这里的DATA_RAW表(其他2台都差不多,场只是名称不同)详细的表结构:
CREATE TABLE IF NOT EXISTS `data_raw` (
`SRV_TIMESTAMP` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`DEVICE_ID` char(5) NOT NULL,
`VOLTAGE` decimal(2,0) NOT NULL,
`CURRENT` decimal(2,0) NOT NULL,
`PHASE` decimal(3,0) NOT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COMMENT='RAW DATA COMING FROM DEVICE IN A SINGLE TIMESLOT';
ALTER TABLE `data_raw`
ADD PRIMARY KEY (`DEVICE_ID`,`SRV_TIMESTAMP`) COMMENT 'PRIMARY KEY',
ADD KEY `IDX_DEVICE_ID` (`DEVICE_ID`);
现在的问题:
我需要计算的各种数据,并以这样做,我加入提供气象数据,并与太阳数据电气数据如下:
SELECT
D.VOLTAGE,
D.CURRENT,
S.SUNPOWER1,
S.SUNAZIMUTH,
W.CLOUDS,
W.TEMPERATURE
FROM
DATA_RAW AS D
JOIN SUN_DATA AS S ON
S.SRV_TIMESTAMP=D.SRV_TIMESTAMP
AND S.DEVICE_ID=D.DEVICE_ID
LEFT JOIN WEATHER_DATA AS W ON
HOUR(W.SRV_TIMESTAMP)=HOUR(D.SRV_TIMESTAMP)
AND MONTH(W.SRV_TIMESTAMP)=MONTH(D.SRV_TIMESTAMP)
AND YEAR(W.SRV_TIMESTAMP)=YEAR(D.SRV_TIMESTAMP)
AND S.DEVICE_ID=D.DEVICE_ID
ORDER BY D.SRV_TIMESTAMP DESC
此查询时间超过60秒,在DATA_RAW和SUN_DATA只是40.000行和WEATHER_DATA 150行。
将字段顺序更改为联接没有任何好处。 错误在哪里?
如果不知道表格和索引,很难确切知道出了什么问题,因此您可能希望使问题更加简洁并提供相关信息,但一个显而易见的问题是您在过滤子句中使用函数。即使你有索引,当你使用'HOUR(W.SRV_TIMESTAMP)'之类的东西时,你也可以防止任何索引被使用,并且你将拥有一个全表扫描功能,并将该功能应用于每一行。 – 2014-08-31 19:29:35
1.你的问题很难阅读。请将其分成多个段落。 2.您已经描述了这些表格,但尚未指定您拥有的索引。 3.如果可能的话,提供一个带有真实数据的数据库转储(不需要是实际的数据,但类似的东西) – some 2014-08-31 19:30:16
我已经遵循@some建议,希望现在的问题更容易阅读。 – 2014-08-31 21:56:09