我正在開發專業的基於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