Ailef
Ailef

Reputation: 7906

Help needed optimizing MySQL SELECT query

I have a MySQL table like this one:

day     int(11) 
hour    int(11)    
amount  int(11)   

Day is an integer with a value that spans from 0 to 365, assume hour is a timestamp and amount is just a simple integer. What I want to do is to select the value of the amount field for a certain group of days (for example from 0 to 10) but I only need the last value of amount available for that day, which pratically is where the hour field has its max value (inside that day). This doesn't sound too hard but the solution I came up with is completely inefficient.

Here it is:

SELECT q.day, q.amount 
    FROM amt_table q 
    WHERE q.day >= 0 AND q.day <= 4 AND q.hour = (
        SELECT MAX(p.hour) FROM amt_table p WHERE p.day = q.day
    ) GROUP BY day

It takes 5 seconds to execute that query on a 11k rows table, and it just takes a span of 5 days; I may need to select a span of en entire month or year so this is not a valid solution.

Anybody who can help me find another solution or optimize this one is really appreciated

EDIT

No indexes are set, but (day, hour, amount) could be a PRIMARY KEY if needed

Upvotes: 1

Views: 145

Answers (2)

Marko
Marko

Reputation: 512

I think the problem is the subquery in the where clause. MySQl will at first calculate this "SELECT MAX(p.hour) FROM amt_table p WHERE p.day = q.day" for the whole table and afterwards select the days. Not quite efficient :-)

Upvotes: 0

OMG Ponies
OMG Ponies

Reputation: 332521

Use:

SELECT a.day, 
       a.amount
  FROM AMT_TABLE a
  JOIN (SELECT t.day,
               MAX(t.hour) AS max_hour
          FROM AMT_TABLE t
      GROUP BY t.day) b ON b.day = a.day
                       AND b.max_hour = a.hour
 WHERE a.day BETWEEN 0 AND 4

I think you're using the GROUP BY a.day just to get a single amount value per day, but it's not reliable because in MySQL, columns not in the GROUP BY are arbitrary -- the value could change. Sadly, MySQL doesn't yet support analytics (ROW_NUMBER, etc) which is what you'd typically use for cases like these.

Look at indexes on the primary keys first, then add indexes on the columns used to join tables together. Composite indexes (more than one column to an index) are an option too.

Upvotes: 4

Related Questions