我想从表B中删除条目,因此每个A_id
(ID最高的条目)只有一个条目
表A :
+----+------------+
| id | name |
+----+------------+
| 1 | Some name |
| 2 | Other name |
+----+------------+
表B :
+----+-------+------+
| id | stuff | A_id |
+----+-------+------+
| 1 | aab | 1 |
| 2 | aac | 1 |
| 3 | aad | 2 |
| 4 | aae | 1 |
| 5 | aak | 1 |
| 6 | aal | 2 |
+----+-------+------+
我当前的查询(效果很好):
DELETE FROM B
WHERE id NOT IN (SELECT MAX(id)
FROM B
GROUP BY A_id)
将得到正确的结果:
+----+-------+------+
| id | stuff | A_id |
+----+-------+------+
| 5 | aak | 1 |
| 6 | aal | 2 |
+----+-------+------+
但是当表B中有很多行时,它非常慢。是否有任何方法可以提高查询的性能(或者可能以完全不同的方式来做?)
答案 0 :(得分:3)
您正在删除大量行。那就是问题所在。删除操作的开销很大。
如果要删除表中的大量行(并且可能只占百分之几),则重新创建表通常会更快:
select b.*
into temp_b -- actually, I wouldn't use a temporary table in case the server goes down
from b
where b.id = (select max(a.id) from b b2 where b2.id = b.a_id);
truncate table b;
insert into b
select *
from temp_b;
尝试此操作之前,请确保已备份b
或至少将其副本保存在某个地方。
请注意,我更改了NOT IN
的结构。我强烈不鼓励使用NOT IN
,因为当子查询返回NULL
值时语义并不直观。如果只有一个NULL
值,那么WHERE
将永远不会评估为TRUE。即使在这种情况下NULL
值都不是问题,我还是强烈建议您使用其他替代方法,这样在NULL
可能的情况下您就不会有问题。
为了提高SELECT
的性能,您需要在b(a_id, id)
上建立索引。您可能会发现这样的索引有助于您的原始查询。
答案 1 :(得分:2)
您的查询对我来说很好。
您的问题似乎是您拥有大量数据,并需要优化性能的方法。
您可以做的是具体化您的子查询,并确保将max_id编入索引,例如通过使其成为主键。
因此,创建一个临时表Max_B
,并将子查询的结果存储在此表中。然后执行删除操作,然后删除临时表。