MySQL MySQL的性能很慢

时间:2012-10-04 14:46:17

标签: mysql database

我有以下数据库架构: https://dl.dropbox.com/u/37915176/schema.PNG

我在meter_relevation中有超过2百万条记录。数据来自几个电表,这些电表与具有meter_history表的设备(设备)相关联。

我尝试获取特定日期范围的设备数据:

SELECT MR.* 
FROM device AS D, meter_history AS MH, meter AS M, meter_relevation AS MR
WHERE D.Id=MH.Id_Device 
   AND MH.Id_Meter=M.Id 
   AND M.Id=MR.Id_Meter 
   AND D.Id="8" 
   AND MR.Date>="2012-10-04" 
   AND MR.Date<="2012-10-04"

但是性能非常慢,即使指定的日期范围没有记录,我也可以获得10秒。

我尝试使用EXPLAIN,我清楚地看到我的查询不是最优的,在meter_relevation表上列出了总行数,超过2百万:https://dl.dropbox.com/u/37915176/explain.png

有什么建议吗?有一个更好的方法?当然,我可以在客户端做一些工作,并分成几个查询。但我想知道单个SELECT查询是否有更好的方法。

4 个答案:

答案 0 :(得分:1)

我建议您尝试在列上添加索引:

D.Id
MH.Id_Device 
MH.Id_Meter
M.Id 
MR.Id_Meter 
MR.Date

答案 1 :(得分:1)

如果这是您正在运行的查询,则它看起来不是最佳的。你真的不需要D表,不是吗?看看MH.Id_device = "8"如何满足设备上的条件。

但假设还有其他字段未显示,那么让我们重写:

SELECT MR.*
    FROM meter_relevation AS MR
    JOIN meter AS M ON ( M.Id = MR.ID_Meter )
    JOIN meter_history AS MH ON ( MH.Id_Meter = M.Id )
    JOIN device AS D ON ( D.Id=MH.Id_Device AND D.Id = "8" )
WHERE 
    MR.Date BETWEEN "2012-10-04" AND "2012-10-04";

所以我们需要索引。第一个是最重要的

CREATE INDEX mr_ndx     ON meter_relevation ( Date, Id_Meter );

但是请尝试删除上面的索引并改为使用:

CREATE INDEX mr_ndx     ON meter_relevation ( Id_Meter, Date );


CREATE INDEX m_ndx      ON meter(Id); -- This probably already exists
CREATE INDEX mh_ndx     ON meter_history( Id_Device, Id_Meter );
CREATE INDEX d_ndx      ON device (Id); -- This too probably already exists

上面的内容,如果这样编写,就等同于(但MySQL应该意识到这一点,所以我认为这不会让你的速度减慢太多)

SELECT MR.*
    FROM meter_relevation AS MR
    JOIN meter AS M ON ( MR.ID_Meter = M.Id)
    JOIN meter_history AS MH ON (MH.Id_Device = "8" AND MH.Id_Meter = M.Id)
WHERE 
    MR.Date BETWEEN "2012-10-04" AND "2012-10-04";

答案 2 :(得分:0)

我的猜测是因为缺少索引而正在进行表扫描。尝试注释掉这一位,看看它是否有所改善:

AND MR.Date>="2012-10-04" 
AND MR.Date<="2012-10-04"

如果是这样,那么在MR.Date上尝试索引。

答案 3 :(得分:0)

索引肯定会有所帮助。适当地运行EXPLAIN和索引。索引所有外键和日期字段。这里有关于JOIN索引的更多细节。

http://hackmysql.com/case4

通常,最简单的解决方案是避免过于复杂的查询。你加入了4张桌子。你真的需要来自所有4个表的所有数据吗?我通常会避免使用SELECT *查询来强制自己确保我只获取所需的数据。