【问题标题】:DELETE-Queries are taking too much timeDELETE - 查询花费了太多时间
【发布时间】:2018-07-23 14:12:27
【问题描述】:

我在 Galera 集群(3 个服务器)中有一个 MariaDB 表 subject_message_new,用于注册用户已阅读消息。我们有31000 用户和数百万条消息,所以表非常大(现在多达 150 万条记录)。如果更新消息,则必须删除所有带有$id_message 的读取条目。

用户还可以将消息复制到另一个主题,以便消息 ($id_message) 引用原始消息 (id_message_org),同时必须删除连接的原始消息中的 the-read-entry

这是我的 MySQL 表:

Kolom   Type    Commentaar
id  bigint(20) Auto nummering    
id_message  int(11)  
id_subject  int(11) NULL     
nr_user int(11)  
datetime    datetime     

Indexen
PRIMARY id
INDEX   nr_user
INDEX   id_message
INDEX   id_subject

Foreign keys
id_message  subject_message(id_message) CASCADE CASCADE
nr_user users(nr_user)  CASCADE CASCADE
id_subject  subject(id_subject) CASCADE CASCADE 

我有一个在消息更改后调用的 PHP 函数

function message_new($id_message,$id_subject){
 global $conn;
 mysqli_query($conn,"DELETE FROM subject_message_new WHERE (id_message='$id_message' AND id_subject='$id_subject') OR id_message IN(SELECT id_message FROM subject_message WHERE id_message_org='$id_message')");
}

如果我将子查询拆分为2 x DELETE-查询,则需要2 x 6-12 秒...

此功能(查询)在生产中花费的时间太长,最长可达 6-12 秒。 有人可以给我建议如何调整吗?或者让它更好地工作?

【问题讨论】:

  • OR和IN都很贵
  • 看看EXPLAIN DELETE ...(见dev.mysql.com/doc/refman/5.6/en/explain.html)。这应该告诉你慢的部分在哪里
  • 您的问题在于您的子选择。您必须找到一种方法来忽略它或优化它。首先,您需要确保“subject_message.id_message”被编入索引。然后为了清楚起见将它们分开。执行“OR”之前的所有内容,然后执行它之后的所有内容。然后我将专注于优化我的子选择(“OR”之后的查询)。尝试减少记录,添加索引等。确实,OR 和 IN 很昂贵,但并不禁止,您只是没有奢侈在查询中抛出任何您想要的东西,您实际上需要“彻底考虑并优化”它。
  • 提示:DELETE 查询也可能受到 SQL 注入攻击,即所谓的基于时间的 SQL 注入(通过滥用 MySQL 的 SLEEP() 函数)

标签: php mysql query-optimization mariadb


【解决方案1】:

问题在于删除方法中的子查询。将单个语句拆分为两个查询显然会提高性能。

DELETE FROM subject_message_new WHERE id_message='$id_message' AND id_subject='$id_subject';

DELETE from subject_message_new smn INNER JOIN subject_message sm on smn.id_message = sm.id_message_org;

注意:在执行选择、更新或删除操作

时,我们应该尽量选择JOIN而不是子查询

然后在 subject_message_new 表的 id_message 和 id_subject 列中添加索引。并在 subject_message 中为列 id_message_org 添加索引。这绝对可以解决问题。

【讨论】:

  • 感谢您的回复!正如我写的那样,将查询分成两个 DELETE_queries 没有帮助,它将花费两倍的时间,所以子查询不是问题,DELETE 查询是问题。我了解 JOIN 具有更好的性能。你写了我必须添加几个索引,但是列已经被索引了,还有 id_message_org。
【解决方案2】:

也许使用多表 UPDATE/DELETE 语法重写查询会有所帮助, 会是这样的:

DELETE  subject_message_new.* FROM subject_message_new
    LEFT JOIN subject_message
    ON (subject_message_new.id_message = subject_message.id_message)
    WHERE (subject_message_new.id_message='$id_message'
    AND subject_message_new.id_subject='$id_subject')
    OR  id_message.id_message_org='$id_message';

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 2012-06-04
    • 1970-01-01
    相关资源
    最近更新 更多