Apache服务器没有显示任何性能问题,尽管MySQL服务器具有很强的计算能力,但我无法在不到60秒的时间内执行查询。我已经使用了所有工具(键和索引)并正确设计了查询(我希望),但我无法理解错误。
我在数据库设计方面的经验主要来自Oracle和SQL Server,我对MySQL的经验非常有限(专业)。
服务器硬件:在Windows Server 2008上运行2x Xeon CPU 64位+ 4GB RAM,是的,Windows安装在Windows2008上,因为它是我非常了解的平台。
数据库非常简单:
表1:DATA_RAW由托管电气参数的多个字段以及包含数据raw的TIMESTAMP的SRV_TIMESTAMP字段组成,DEVICE_ID字段包含远程设备ID。
所有远程设备每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行。
将字段顺序更改为连接并不会带来任何好处。 错误在哪里?
答案 0 :(得分:1)
我做了一些测试,并在我的硬件上查询了不到0.2秒(Intel Xeon CPU E3-1220(4核),16GB,运行Linux和MariaDb(直接替换mysql))
首先,我创建了如下表格。请注意,我增加了device_id中的字符数,并更改了十进制类型的精度和比例以匹配您提供的示例数据。我还在data_raw中添加了一个字段weatherts
,其中包含设备最新天气报告的时间戳。 (您可以在插入原始数据之前查询最新的天气报告时间戳,并且还可以在获得天气报告时更新以前记录的时间戳)。
CREATE TABLE IF NOT EXISTS `data_raw` (
`SRV_TIMESTAMP` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`DEVICE_ID` char(8) NOT NULL,
`VOLTAGE` decimal(3,0) NOT NULL,
`CURRENT` decimal(2,1) NOT NULL,
`PHASE` decimal(3,2) NOT NULL,
`weatherts` timestamp
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COMMENT='RAW DATA COMING FROM DEVICE IN A SINGLE TIMESLOT';
CREATE TABLE IF NOT EXISTS `data_sun` (
`SRV_TIMESTAMP` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`DEVICE_ID` char(8) NOT NULL,
`SUNPOWER` decimal(10,0) NOT NULL,
`SUNAZIMUTH` decimal(4,1) NOT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COMMENT='SUN DATA';
CREATE TABLE IF NOT EXISTS `data_weather` (
`SRV_TIMESTAMP` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`DEVICE_ID` char(8) NOT NULL,
`CLOUDS` decimal(2,0) NOT NULL,
`TEMPERATURE` decimal(3,1) NOT NULL
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COMMENT='WEATHER DATA';
我创建了一个脚本,创建16个单位的伪造数据,每隔30秒创建一次data_raw和data_sun,每小时创建一次data_weather,导致data_raw和data_sun各有46080行数据,data_weather中有384行。
使用SELECT * FROM data_raw
查询 data_raw 大约需要0.10秒。
我尝试了查询的第一部分,在那里我加入了data_raw和data_sun。没有索引需要永远,所以我在data_sun上创建了一个索引:
CREATE UNIQUE INDEX SUN_PKEY ON data_sun (SRV_TIMESTAMP, DEVICE_ID);
现在,下面的查询大约需要0.10秒。
SELECT
D.SRV_TIMESTAMP, D.DEVICE_ID, D.VOLTAGE, D.CURRENT, D.PHASE,
S.SUNPOWER, S.SUNAZIMUTH
FROM data_raw AS D
LEFT JOIN data_sun AS S ON
(S.SRV_TIMESTAMP=D.SRV_TIMESTAMP AND S.DEVICE_ID=D.DEVICE_ID);
为了能够进行完整查询,我还在data_weather上添加索引:
CREATE UNIQUE INDEX WEATHER_PKEY ON data_weather (SRV_TIMESTAMP, DEVICE_ID);
现在是时候测试查询了:
SELECT
D.SRV_TIMESTAMP, D.DEVICE_ID, D.VOLTAGE, D.CURRENT, D.PHASE,
S.SUNPOWER, S.SUNAZIMUTH,
W.CLOUDS, W.TEMPERATURE
FROM data_raw AS D
LEFT JOIN data_sun AS S ON
(S.SRV_TIMESTAMP=D.SRV_TIMESTAMP AND S.DEVICE_ID=D.DEVICE_ID)
LEFT JOIN data_weather AS W ON
(D.WEATHERTS = W.SRV_TIMESTAMP AND W.DEVICE_ID=D.DEVICE_ID)
ORDER BY D.SRV_TIMESTAMP, D.DEVICE_ID;
现在我在0.13秒内得到46080行。由于只需要0.10秒来读取data_raw表,我认为它非常好。