0

I have a table with a column when that is of type datetime. I am doing the following filter which can not use and index:
AND DATE_FORMAT(t1.when, '%Y-%m-%d') <= LAST_DAY(now() - interval 1 month )
How can I re-write this so that I can get rid of the DATE_FORMAT that forbids index usage?

2
  • 1
    Have you tried the query without the function (AND t1.when <= LAST_DAY(now() - interval 1 month)? – Christian Ammer Apr 15 '14 at 9:17
  • @ChristianAmmer:I was not sure if it is the same – Jim Apr 15 '14 at 9:42
2

The comment from @ChristianAmmer is the key to answering your question. Why ???

First look the the WHERE clause

DATE_FORMAT(t1.when, '%Y-%m-%d') <= LAST_DAY(now() - interval 1 month )

You are forcing mysqld to evaluate DATE_FORMAT(t1.when, '%Y-%m-%d') for every row and comparing each result to LAST_DAY(now() - interval 1 month ). That quickly adds wear-and-tear on the query. I have discussed this before (See my answer to What happens when we take a timediff between timestamp and datetime).

When comparing to LAST_DAY(now() - interval 1 month ), there is no need to do the DATE_FORMAT function against t1.when. Look at what actually happens when you do:

  • You evaluate DATE_FORMAT(t1.when, '%Y-%m-%d') and the result is a string
  • The string has to be converted back to a DATE
  • That converted DATE is then compared to LAST_DAY(now() - interval 1 month )

These steps must be done for every row.

To remove those steps, just switch the WHERE clause to have

AND t1.when <= LAST_DAY(now() - interval 1 month)

as @ChristianAmmer specified.

That way it compares DATE to DATE without any string manipulate or function call.

To answer your last comment

@ChristianAmmer:I was not sure if it is the same

The comparison of the result is the same, but the way the comparison is executed is not.

Doing it with AND t1.when <= LAST_DAY(now() - interval 1 month) will always be faster. Leaving the t1.when on the left side of the comparison (left side of the equal sign) obligates the MySQL Query Optimizer to try using the index. Using a function call on the left side of the comparison eliminates index usage.

CONCLUSION : Go ahead an d use AND t1.when <= LAST_DAY(now() - interval 1 month)

UPDATE 2014-04-15 10:46 EDT

To further prove function calls on the left side confuses the MySQL Query Optimizer, I have other posts going back to 2011 that discuss how searching a FULLTEXT index cause the MySQL Query Optimizer to stop using other indexes (since you have to use the MATCH function on the left side).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.