If you have query that cannot be cached, you can split it into two simpler queries. The first query will return row IDs based on non-cacheable functions; the second query will do the rest. So at least the second query will be cached.
Using your example, you can make two queries:
- SELECT ID FROM table WHERE appointment_date >= NOW();
... so your application will collect IDs. If there are any IDs returned, combine them to a coma-separated string and run the second query:
- SELECT * FROM table WHERE ID IN (".$ids.");"
Of course, your query is quite simple, but if you have very complex and large queries, you can split them programmatically. For example, you may use a regular expression and a function to find out whether the query is non-cacheable and it is worth splitting it. For example, you can use the following PHP function for that purpose:
function query_cannot_be_cached($query)
{
return preg_match("/\b(?:AES_DECRYPT|AES_ENCRYPT|BENCHMARK|CONNECTION_ID|CONVERT_TZ|CURDATE|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURTIME|DATABASE|ENCRYPT|FOUND_ROWS|GET_LOCK|IS_FREE_LOCK|IS_USED_LOCK|LAST_INSERT_ID|LOAD_FILE|MASTER_POS_WAIT|NOW|PASSWORD|RAND|RANDOM_BYTES|RELEASE_ALL_LOCKS|RELEASE_LOCK|SLEEP|SYSDATE|UNIX_TIMESTAMP|USER|UUID|UUID_SHORT)\b *\(/i", $query);
}
Another solution is just to avoid server-side comparison (Now()) and use client-side comparison only. We use this approach in our server. If a query return just a few data, you can not split it. But if it returns lot of data split it as I have explained below. So your query will be like that:
- SELECT appointment_date, id FROM table;
or you can set a date granularity (say, one month, one-day or one-hour) and add it to the comparison. This granular date should be calculated in advance by your software, for example:
- SELECT appointment_date, id FROM table WHERE appointment_date > '2017-05-10';
(this '2017-05-10' value should be calculated by your software, it changes only once a day).
and then you receive the appointment_date and compare it with current time on client side. If the time matches, you run the second query as shown in the example #2 above.
Of course, these examples are very simple, we are using much more complex queries in our server.