简体   繁体   中英

Speed up the SQL query

I have stored temperatures in a MySQL database. The table is called temperatures . It contains, for example, the columns dtime and temperature . The first one is the time the temperature was measured (the column type is DATETIME ) and the latter, well, apparently the temperature (the type is FLOAT ).

At the moment I use the following query to fetch the temperatures in a certain period.

SELECT dtime, temperature 
FROM temperatures 
WHERE dtime BETWEEN "2012-11-15 00:00:00" AND "2012-11-30 23:59:59" 
ORDER BY dtime DESC

I'd like to add the average temperature of the day in the results. I tried the following.

SELECT 
    dtime AS cPVM,
    temperature,
    (
        SELECT AVG(temperature) 
        FROM temperatures 
        WHERE DATE(dtime) = DATE(cPVM)
    ) AS avg
FROM temperatures 
WHERE dtime BETWEEN "2012-11-15 00:00:00" AND "2012-11-30 23:59:59" 
ORDER BY dtime DESC

Works ok, but this is really, really slow. Fetching the results in that period takes about 5 seconds, when the first one (without the averages) is done in 0.03 seconds.

SELECT DATE(dtime), AVG(temperature) 
FROM temperatures 
WHERE DATE(dtime) BETWEEN "2012-11-15" AND "2012-11-30" 
GROUP BY DATE(dtime) 
ORDER BY dtime DESC

This one however is done in 0.04 seconds.

How do I fetch the average temperatures more efficiently?

Use a join instead of a correlated subquery:

SELECT dtime, temperature, avg_temperature
FROM temperatures 
JOIN (
    SELECT DATE(dtime) AS date_dtime, AVG(temperature) AS avg_temperature
    FROM temperatures
    WHERE dtime >= '2012-11-15' AND dtime < '2012-12-01'
    GROUP BY DATE(dtime)
) AS avg_t
ON date_dtime = DATE(dtime)
WHERE dtime dtime >= '2012-11-15' AND dtime < '2012-12-01'
ORDER BY dtime DESC

Since your first query is very efficient already, let's use it as a starting point. Depending on the size of the result sets it produces, querying the results of your first query can still be very efficient.

Your third query also seems to run very efficiently, so you can fall back to that if my proposed query doesn't perform well enough. The reason I like it is because you can take the original query as a parameter of sorts (minus the ORDER BY ) and plug it into this one, which shows the average temperature from the date range of the original query:

SELECT
    DATE(dtime) AS day_of_interest,
    AVG(temperature) AS avg_temperature
FROM
    (
        -- Your first query is here, minus the ORDER BY clause
        SELECT 
            dtime,
            temperature 
        FROM 
            temperatures 
        WHERE 
            dtime BETWEEN "2012-11-15 00:00:00" AND "2012-11-30 23:59:59" 
        -- ORDER BY irrelevant inside subqueries, only slows you down
        -- ORDER BY 
            -- dtime DESC
    ) AS temperatures_of_interest
GROUP BY
    day_of_interest
ORDER BY
    day_of_interest DESC

If this query runs "efficiently enough" ™ for you, then this could potentially be an easier solution to code up and automate than perhaps some others.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM