I have the following database schema: https://dl.dropbox.com/u/37915176/schema.PNG
I have more than 2 millions records in meter_relevation. The data is coming from several electrical meters which are associated to appliances (devices) with the meter_history table.
I try to get the data of a device for a specific date range:
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"
But the performance are very slow, I can get 10 seconds even if there are no record for the specified date range.
I tried EXPLAIN and I clearly see that my query is not optimal, on the meter_relevation table is listing the total number of rows, more than 2 millions: https://dl.dropbox.com/u/37915176/explain.png
Any suggestions? There is a better way? Of course I could do some work on the client side and split in several queries. But I would like to know if there are better way for a single SELECT query.
If that is the query you're running, it looks sub-optimal. You don't really need the D table, or do you? Seeing as how the condition on device could be satisfied by MH.Id_device = "8".
But supposing there are other fields which aren't shown, then let's rewrite:
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";
So we need indexes. The first is the most important
CREATE INDEX mr_ndx ON meter_relevation ( Date, Id_Meter );
But try also deleting the index above and using instead:
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
The above, if written just like that, is equivalent (but MySQL should realize this, so I don't think it's slowing you too much) to
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";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With