【问题标题】:How to improve MySQL DELETE query performance如何提高 MySQL DELETE 查询性能
【发布时间】:2013-03-28 17:03:53
【问题描述】:

使用:Windows 上的 MySQL 5.6,在 my.ini 中使用默认配置文件设置

表:datatbl1

row_id   | emailaddr    | valid
--------------------------------  
INT, PK  | VARCHAR(255) | BIT

emailaddr 和 row_id 列都定义了一个索引。

表中有 600,000 行,目标是删除重复项。查询是:

delete dt2 from datatbl1 dt1 JOIN datatbl1 dt2 on (dt1.emailaddr = dt2.emailaddr) and (dt1.row_id < dt2.row_id);

在我的系统上,完成这个查询大约需要 15 分钟,我在任务管理器中观察 mysqld 进程,处理器使用率一直是 100%,但内存使用量从未超过 140MB,尽管大约有 3GB已安装的内存 (RAM) 和充足的可用内存。

问题:

  1. 我可以更改一些配置参数来提高性能吗?
  2. 能否重写查询本身以提高性能?
  3. 执行这个包含 1 到 200 万行的查询的合理时间是多少?

请记住,此查询稍后需要应用于其他表,即删除 datatbl1 中与具有相同表结构的其他表(datatbl2、datatbl3、datatbl4 等)匹配的记录。

在我客户的系统上,相同的查询需要 2 个小时。不同的是他有一个普通的硬盘,而我有一个SSD。

该应用程序是具有 Delphi 前端的客户端服务器应用程序,旨在供普通用户在 Windows PC 上使用,因此 MySQL 几乎总是在最终用户 Windows PC 上运行。

提前致谢。

编辑: 请求的解释输出是:

mysql> explain delete dt2 from datatbl1 dt1 JOIN datatbl1 dt2 on (dt1.emailaddr
= dt2.emailaddr) and (dt1.row_id < dt2.row_id);
+----+-------------+-------+-------+------------------------------+-------------
+---------+--------------------------+------+-------------+
| id | select_type | table | type  | possible_keys                | key
| key_len | ref                      | rows | Extra       |
+----+-------------+-------+-------+------------------------------+-------------
+---------+--------------------------+------+-------------+
|  1 | SIMPLE      | dt1   | index | PRIMARY,ixemailaddr,ixrow_id | ixemailaddr
| 257     | NULL                     |    1 | Using index |
|  1 | SIMPLE      | dt2   | ref   | PRIMARY,ixemailaddr,ixrow_id | ixemailaddr
| 257     | emailmgrdb.dt1.emailaddr |    1 | Using where |
+----+-------------+-------+-------+------------------------------+-------------
+---------+--------------------------+------+-------------+
2 rows in set (0.01 sec)

【问题讨论】:

  • 这是一次性事件,因为您没有使用 UNIQUE 关键字?
  • 您可以发布EXPLAIN 查询结果吗?
  • @piotrekkr : 解释发布的结果。
  • @SteveF - 问题是你将来会使用UNIQUE 来避免这个问题,因此只需要这样做一次吗?
  • @SteveF - 恕我直言,我认为您应该重新设计数据库,使其使用 3NF

标签: mysql performance


【解决方案1】:

也许这个查询会更快:

DELETE dt1.*
FROM datatbl1 dt1
JOIN (SELECT emailaddr, MIN(row_id) minrow
      FROM datatbl1
      GROUP BY emailaddr) dt2
USING (emailaddr)
WHERE dt1.row_id > dt2.minrow

原始查询中中间表的大小为 O(n^2)(因为它将每一行与后面的所有重复项连接起来),但这个是 O(n)(因为它只连接第一个每组重复项的行及其后面的行)。

这取决于缓慢是在查找行还是执行所有删除。您可以通过执行 SELECT 而不是 DELETE 并注意性能差异来发现这一点。

【讨论】:

  • 效果很好。查询现在在 4 秒内完成并产生正确的结果。太棒了!
  • 问题 - 删除 row_id 上的索引会产生负面影响差异吗?它已经是 PRIMARY KEY。
  • 类似地,在同一个数据库中,有没有办法改进这个查询:“update datatbl1 dt1 join datatbl2 dt2 on (dt1.emailaddr = dt2.emailaddr) set valid = 0; "
  • 主键是自动索引的,所以不需要单独的索引。我认为只要两个表在 emailaddr 上都有索引,更新查询就应该可以正常工作。
【解决方案2】:

您是否尝试过将row_id 比较移动到WHERE 子句?

DELETE dt1
FROM datatbl1 dt1
INNER JOIN datatbl1 dt2 ON dt1.emailaddr = dt2.emailaddr
WHERE dt1.row_id > dt2.row_id

【讨论】:

    猜你喜欢
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2023-04-08
    • 1970-01-01
    • 2023-03-14
    • 2014-11-09
    • 2015-06-06
    相关资源
    最近更新 更多