简体   繁体   English

100%的MySQL Query Pegs Server-有时

[英]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. 我有一个MySQL查询,它运行得非常非常慢,并且一执行就会将服务器使用率固定在100%。

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. 有时,它可以正常工作,并且几乎立即返回结果,但其他时候则需要很长时间(超过15分钟)和100%的服务器资源才能返回结果。

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. 您必须为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). 第三:在这个特定查询中,据我所知,您正在将“剩余”重新加入自身,只是为了找到max(date)。 Why not just use a GROUP BY? 为什么不只使用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.) (我不确定recordID标识什么。从查询中可以看出,您可以在具有相同recordid的提醒中包含多个记录。)

Five: You'll probably get best performance if you have indexes on reminders(owner, date) and marketingDatabase(id). 五:如果在提醒(所有者,日期)和marketingDatabase(id)上具有索引,则可能会获得最佳性能。

Six: Just by the way, if "do_not_call" and followUp are true/false, they should be booleans and not varchars. 六:顺便说一句,如果“ do_not_call”和followUp是true / false,则它们应该是布尔值而不是varchars。 You're just wasting disk space and execution time processing "true" instead of a boolean TRUE. 您只是在浪费磁盘空间和执行时间,而不是布尔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. 在绝对最坏的情况下,使它们成为char(1),T或F。

There are times when you need embedded queries, but they should be a last resort. 有时您需要嵌入式查询,但是它们应该是不得已的方法。

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

CREATE INDEX someNameYouChoose ON reminders(owner);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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