0

In my database, there is table called Profile which has a DATETIME field called birthday.

I want to query all the records that has birthday between 05-24 and 06-07 (mm-dd) regardless of what year it is and I used the following query:

DATE_FORMAT(`Profile`.`birthday`, "%m-%d") >= '05-24' 
AND DATE_FORMAT(`Profile`.`birthday`, "%m-%d") <  '06-07'

The problem is by doing this way, the index on birthday column has no use, the query is too slow and I want to improve the speed of my query

Please show me if there is any workaround that could still do the job and improve the query performance at the same time

3
  • What version of MySQL are you using? 5.7 allows indexing of "virtual columns" Commented May 24, 2016 at 9:45
  • i'm using mysql 5.6, you can show me another solution Commented May 24, 2016 at 9:49
  • its a good idea to use virtual columns. use virtual persitent column, so you can also use a index on it Commented May 24, 2016 at 11:57

2 Answers 2

2

Yes,

the reason is that you use a FUNCTION on a field in WHERE. This means that MySQL must read all Records of the Table (FULL TABLE SCAN).

You can add a new field birthday2 where you store only day and month with a normalized year like

UPDATE yourTable set birthday2 = DATE_FORMAT(Profile.birthday, "%m-%d-0001");

Ten you can select like

SELECT * from yourTable
WHERE birthday2 BETWEEN ''05-24-0001' AND '06-07-001';

And if you set a index on this field it will be used

Sign up to request clarification or add additional context in comments.

3 Comments

Hi @Bernd Buffen, i have problem when using between. explain (SELECT * from profiles WHERE birthday2 BETWEEN '0001-01-01' AND '0001-03-06' ) it using index condition. But explain (SELECT * from profiles WHERE birthday2 BETWEEN '0001-01-01' AND '0001-06-06' ) Using where.
whats the problem?
Here is image my screen. link and link. If you require any further information, contact me. Thank you!
0

Add another column

mmdd CHAR(5) CHARACTER SET ascii
and
INDEX(mmdd)

Set it using an UPDATE with SET mmdd = DATE_FORMAT(..., "%m-%d")

As a string (CHAR), it would compare 'correctly' unless you wrap around a year boundary (eg, November to February).

For 5.6 -- do it explicity.
For 5.7 or MariaDB -- use virtual column.

Keep in mind that if your date range is "too big" (somewhere around 2 months), the optimizer will ignore the index and do a full table scan. This is deliberate, and actually optimal.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.