I’ve been at this for a few days now trying different methods to reduce the 95-135% CPU load due to a recent AJAX script, calling this query:
SELECT COUNT(*) as total FROM users WHERE last_access >= DATE_SUB(NOW(), INTERVAL 1 MINUTE) ORDER BY last_access DESC LIMIT 16
And I have tried COUNT(id)
to reduce table scan times, I added LIMIT
and ORDER BY
, I think it improved but I can’t tell. I am monitoring top -P on my BSD box, and the CPU has been spiking quite high almost killing apache too, while relying on that for my query testing.
We have a jquery bit that queries the the AJAX script and returns a table count according to last users online with a 15 second interval on jquery-side (1 minute on the query statement). It was fine for a day, then noticed the server was running overtime and fans going haywire.
We ended up removing MySQL 5.7 and installing MariaDB 12.4 – and a huge difference that made, however while its sitting at reduced load by ~20% CPU, its struggling too.. so the query is bad. I disabled the script and sure enough, CPU went down to 15-30% avg, however this is a big part of our website’s UX. This simply reports (455 online) for example, and updates the text every 15 seconds (dynamically).
My question is.. due to the 15 second interval hits to the SELECT(*)
statement on a table of 9600 records, how can I optimize this so the SQL server doesn’t crash and suck up all available memory?
I didn’t include the script as it works wonderfully, the query is the issue but will provide if needed.
This is our only AJAX script on the site. No other AJAX calls are made.
Kind regards,
2
Answers
I don’t think the SQL-query itself is the problem here. Adding ORDER BY and LIMIT should not make any difference since there is only one row to sort and limit. What you could think about is to add an index for the last_access column.
Depending on your website traffic, I think the problem is the way you’ve designed your system. You’re saying the client is requesting your server every 15s which is asking your database for numbers of users last minute. Imagine having 1 000 users online, in that case, you will have 66 queries per second.
In this case, you should consider implementing a cache. You tagged your post with PHP, Memcached is fairly easy to implement in PHP. Cache your SQL-query for 15 seconds and your database server will only have 0.06 queries per second instead.
For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause.
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_count
Be sure to have this on the table
COUNT(id)
is, if anything, slower. It is the same asCOUNT(*)
, plus checkingid
for beingNOT NULL
.How many different threads are there?
Let’s look at what that query takes —
In other words, have you investigated which process is taking most of the CPU?