简体   繁体   中英

MySQL Query Pegs Server at 100% - Sometimes

I've got a MySQL query that runs very, very slowly and pegs the server usage at 100% as soon as it's executed....sometimes.

Here's the query:

SELECT DISTINCT r1.recordID, 
       (SELECT MAX(r2.date) 
            FROM reminders as r2 
            WHERE r2.owner = '$owner' 
                AND r2.recordID = r1.recordID 
                AND r2.status = 'Active' 
                AND r2.followUp != 'true' 
            ORDER BY r2.date DESC LIMIT 1) as maxDate 
    FROM reminders as r1 
    WHERE r1.owner = '$owner' 
        AND (SELECT MAX(r2.date) 
                 FROM reminders as r2 
                 WHERE r2.recordID = r1.recordID 
                     AND r2.status = 'Active' 
                     AND r2.followUp != 'true' 
                 ORDER BY r2.date DESC LIMIT 1) <= '$date' 
        AND (SELECT do_not_call 
                 FROM marketingDatabase 
                 WHERE id = r1.recordID) != 'true' 
        AND r1.status = 'Active' 
    ORDER BY maxDate DESC

I'm not sure if it's a poorly written query (might be...I'm new at this) or something else. Sometimes it works fine and results are returned almost instantly but other times it takes a long time (15+ minutes) and 100% server resources to return the results.

Any idea why this could be happening? Anything I can do to the query to prevent this?

Thanks in advance!

[EDIT]

Here's the EXPLAIN.

Array
(
    [0] => Array
        (
            [id] => 1
            [select_type] => PRIMARY
            [table] => r1
            [type] => ALL
            [possible_keys] => 
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 2073
            [Extra] => Using where; Using temporary; Using filesort
        )

    [1] => Array
        (
            [id] => 4
            [select_type] => DEPENDENT SUBQUERY
            [table] => marketingDatabase
            [type] => eq_ref
            [possible_keys] => PRIMARY
            [key] => PRIMARY
            [key_len] => 4
            [ref] => teleforce.r1.recordID
            [rows] => 1
            [Extra] => 
        )

    [2] => Array
        (
            [id] => 3
            [select_type] => DEPENDENT SUBQUERY
            [table] => r2
            [type] => ALL
            [possible_keys] => 
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 2073
            [Extra] => Using where
        )

    [3] => Array
        (
            [id] => 2
            [select_type] => DEPENDENT SUBQUERY
            [table] => r2
            [type] => ALL
            [possible_keys] => 
            [key] => 
            [key_len] => 
            [ref] => 
            [rows] => 2073
            [Extra] => Using where
        )
)

Several things could make this query slow.

One: In general, the first thing to check is indexes. You have three embedded queries that have to be executed for each record in r1. If any of these are not able to effectively use an index and have to process a large number of records, this query will be very slow. Review your indexes, and use "explain" to see what's being used.

Two: Embedded queries tend to be slower than joins. See if you can't transform some of your embedded queries to joins.

Three: In this particular query, you're joining "remainders" back on itself, as far as I can figure out, just to find max(date). Why not just use a GROUP BY? My step 1 to improving this query would be:

select r1.recordID, max(r1.date) as maxdate
from reminders as r1
where r1.owner=$owner and r1.status='Active' and r1.followUp!='true'
and (SELECT do_not_call FROM marketingDatabase WHERE id = r1.recordID) != 'true'
group by r1.recordID
having max(r1.date)<=$date
order by maxdate desc

I don't have your database to test this, but I think it would give the same results.

Four: I'd turn the other embedded query into a join. Like:

select r1.recordID, max(r1.date) as maxdate
from reminders as r1
join marketingDatabase as m on m.id=r1.recordID
where r1.owner=$owner and r1.status='Active' and r1.followUp!='true'
and m.do_not_call != 'true'
group by r1.recordID, r1.owner
having max(r1.date)<=$date
order by maxdate desc

(I'm not sure what a recordID identifies. It appears from your query that you can have multiple records in reminders with the same recordid.)

Five: You'll probably get best performance if you have indexes on reminders(owner, date) and marketingDatabase(id).

Six: Just by the way, if "do_not_call" and followUp are true/false, they should be booleans and not varchars. You're just wasting disk space and execution time processing "true" instead of a boolean TRUE. And you create the problem of mis-spellings, like "ture" or "True". At the absolute worst, make them a char(1), T or F.

There are times when you need embedded queries, but they should be a last resort.

尝试使用以下命令在reminders.owner上创建索引

CREATE INDEX someNameYouChoose ON reminders(owner);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM