当前位置: 首页 > 面试题库 >

删除匹配行的更快方法?

暴绪
2023-03-14
问题内容

关于数据库,我是一个相对新手。我们正在使用MySQL,而我目前正在尝试加速似乎需要一段时间才能运行的SQL语句。我四处寻找类似问题,但没有找到。

目的是删除表A中表B中具有匹配ID的所有行。

我目前正在执行以下操作:

DELETE FROM a WHERE EXISTS (SELECT b.id FROM b WHERE b.id = a.id);

表a中约有10万行,表b中有约22k行。列“ id”是两个表的PK。

在我的测试箱上运行此语句大约需要3分钟-Pentium D,XP SP3、2GB内存,MySQL
5.0.67。在我看来,这很慢。也许不是,但是我希望加快速度。是否有更好/更快的方法来完成此任务?

编辑:

一些其他信息可能会有所帮助。表A和B具有与创建表B相同的结构:

CREATE TABLE b LIKE a;

表a(以及表b)具有一些索引,以帮助加快对其执行的查询。同样,我还是DB工作的相对新手,现在仍在学习。我不知道这会对事物产生多大的影响(如果有的话)。我认为它确实有效果,因为索引也必须清理,对吗?我也想知道是否还有其他数据库设置可能会影响速度。

另外,我正在使用INNO DB。

以下是一些可能对您有帮助的其他信息。

表A具有与此类似的结构(我对此做了一些消毒):

DROP TABLE IF EXISTS `frobozz`.`a`;
CREATE TABLE  `frobozz`.`a` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `fk_g` varchar(30) NOT NULL,
  `h` int(10) unsigned default NULL,
  `i` longtext,
  `j` bigint(20) NOT NULL,
  `k` bigint(20) default NULL,
  `l` varchar(45) NOT NULL,
  `m` int(10) unsigned default NULL,
  `n` varchar(20) default NULL,
  `o` bigint(20) NOT NULL,
  `p` tinyint(1) NOT NULL,
  PRIMARY KEY  USING BTREE (`id`),
  KEY `idx_l` (`l`),
  KEY `idx_h` USING BTREE (`h`),
  KEY `idx_m` USING BTREE (`m`),
  KEY `idx_fk_g` USING BTREE (`fk_g`),
  KEY `fk_g_frobozz` (`id`,`fk_g`),
  CONSTRAINT `fk_g_frobozz` FOREIGN KEY (`fk_g`) REFERENCES `frotz` (`g`)
) ENGINE=InnoDB AUTO_INCREMENT=179369 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

我怀疑问题的一部分在于此表有许多索引。表B类似于表B,虽然它仅包含列idh

此外,分析结果如下:

starting 0.000018
checking query cache for query 0.000044
checking permissions 0.000005
Opening tables 0.000009
init 0.000019
optimizing 0.000004
executing 0.000043
end 0.000005
end 0.000002
query end 0.000003
freeing items 0.000007
logging slow query 0.000002
cleaning up 0.000002

解决了

感谢所有的答复和评论。他们当然让我考虑了这个问题。 dotjoe致以 荣誉,让我通过问一个简单的问题“还有其他表引用a.id吗?”来解决这个问题。

问题是表A上有一个DELETE
TRIGGER,它调用了存储过程来更新其他两个表C和D。表C的FK返回a.id,并且在存储过程中做了一些与该id相关的事情之后,它有一条语句,

DELETE FROM c WHERE c.id = theId;

我调查了EXPLAIN语句,并将其重写为

EXPLAIN SELECT * FROM c WHERE c.other_id = 12345;

因此,我可以看到它在做什么,并且它提供了以下信息:

id            1
select_type   SIMPLE
table         c
type          ALL
possible_keys NULL
key           NULL
key_len       NULL
ref           NULL
rows          2633
Extra         using where

这告诉我这是一个很痛苦的操作,并且由于要被调用22500次(对于给定的数据集被删除),所以出现了问题。在该other_id列上创建INDEX并重新运行EXPLAIN后,我得到:

id            1
select_type   SIMPLE
table         c
type          ref
possible_keys Index_1
key           Index_1
key_len       8
ref           const
rows          1
Extra

好多了,实际上真的很棒。

我添加了Index_1,删除时间与 mattkemp 报告的时间 一致
。就我而言,这是一个非常微妙的错误,因为在最后一刻鞋拔了一些附加功能。事实证明,正如 丹尼尔 所说,大多数建议的替代DELETE /
SELECT语句最终花费的时间基本上是相同的,并且正如 soulmerge所言
,该语句几乎是我将能够根据所构造的最好的语句我需要做。一旦为另一个表C提供了索引,我的DELETE就很快了。

验尸
从这个练习中学到了两个教训。首先,很明显,我没有利用EXPLAIN语句的功能来更好地了解SQL查询的影响。那是一个菜鸟错误,所以我不会为那个问题而自责。我将从错误中学习。其次,令人反感的代码是“快速完成”心态的结果,而设计/测试不足则导致该问题不会很快出现。如果我生成了几个可观的测试数据集以用作此新功能的测试输入,那么我也不会浪费我的时间,也不会浪费你的时间。我在数据库方面的测试缺乏应用程序方面的深度。现在,我有机会改善这一点。

参考:EXPLAIN声明


问题答案:

从InnoDB删除数据是您可以要求的最昂贵的操作。正如您已经发现的那样,查询本身不是问题-无论如何,大多数查询都将针对相同的执行计划进行优化。

虽然可能很难理解为什么所有情况下的DELETE速度最慢,但是有一个相当简单的解释。InnoDB是一个事务存储引擎。这意味着,如果您的查询在中途中止,则所有记录将仍然存在,就好像什么都没有发生一样。完成后,所有内容将在同一瞬间消失。在DELETE期间,连接到服务器的其他客户端将看到记录,直到完成DELETE。

为了实现这一目标,InnoDB使用了一种称为MVCC(多版本并发控制)的技术。它的基本作用是为每个连接提供整个数据库的快照视图,就像事务的第一条语句开始时一样。为此,InnoDB内部的每个记录可以有多个值-
每个快照一个。这也是为什么在InnoDB上进行计数需要一些时间的原因-这取决于您当时看到的快照状态。

对于您的DELETE事务,将根据您的查询条件识别的每条记录都标记为删除。由于其他客户端可能同时访问数据,因此它无法立即将它们从表中删除,因为它们必须查看各自的快照以保证删除的原子性。

一旦所有记录都标记为删除,就成功提交事务。即使这样,也不能在将所有与快照值一起使用的其他事务(在DELETE事务之前)都结束之前,立即将它们从实际数据页中删除。

因此,实际上,考虑到必须修改所有记录以便以安全交易的方式准备将其删除的事实,您的3分钟并不是真的那么慢。语句运行时,您可能会“听到”硬盘工作。这是由于访问所有行引起的。为了提高性能,您可以尝试增加服务器的InnoDB缓冲池大小,并尝试在删除时限制对数据库的其他访问,从而也减少了InnoDB必须为每个记录维护的历史版本数。有了额外的内存,InnoDB也许能够将您的表(大部分)读到内存中,从而避免了一些磁盘搜索时间。



 类似资料:
  • 我有一个包含“@@@1”的序列的数据帧。我想删除包含此模式的行。 我写了这样的匹配代码: 如果找到匹配项,如何删除该行?

  • 问题内容: 我正在尝试从文本字符串中删除停用词: 我正在处理600万这种字符串,因此速度很重要。分析我的代码,最慢的部分是上面的几行,是否有更好的方法来做到这一点?我正在考虑使用正则表达式之类的东西,但我不知道如何为一组单词写模式。有人可以帮我忙吗,我也很高兴听到其他可能更快的方法。 注意:我尝试过有人建议用来包裹,但这没什么区别。 谢谢。 问题答案: 尝试缓存停用词对象,如下所示。每次调用函数时

  • 本文向大家介绍在Python中删除匹配的元组,包括了在Python中删除匹配的元组的使用技巧和注意事项,需要的朋友参考一下 当需要从两个元组列表中删除匹配的元组时,可以使用列表推导。 列表可用于存储异构值(即,任何数据类型的数据,例如整数,浮点数,字符串等)。 元组列表基本上包含包含在列表中的元组。 列表理解是迭代列表并对其执行操作的一种快捷方式。 以下是相同的演示- 示例 输出结果 解释 定义了

  • 问题内容: 我正在尝试删除mysql表中的孤立条目。 我有2张桌子,像这样: 表: 表: 该和列可以被用来连接表在一起。 我想删除表中所有在表中找不到的行。 因此,使用上面的示例将删除表中的行:3&4(s)。 问题答案: 使用LEFT JOIN / IS NULL: 使用不存在: 使用NOT IN: 警告 只要有可能,就在事务中执行DELETE(假设受支持-IE:不在MyISAM上),以便在出现问

  • 关于这个问题有好几篇帖子,但仍然没有找到答案。这是父类Userr。在@OneToMany关系中,我想删除一个特定的子帐户。 现在,当我通过“删除”查询执行此操作时,我得到以下异常。 组织。springframework。刀。InvalidDataAccessApiUsageException:执行更新/删除查询;嵌套的异常是javax。坚持不懈TransactionRequiredExceptio

  • 问题内容: 我已经使用Python和Django建立了一个在线画廊。我刚刚开始添加编辑功能,从旋转开始。我使用sorl.thumbnail按需自动生成缩略图。 当我编辑原始文件时,我需要清理所有缩略图,以便生成新的缩略图。每个图片有三到四个(我在不同场合有不同的图片)。 我 可以 在文件变量中进行硬编码…但是这很混乱,如果我改变工作方式,则需要重新访问代码。 理想情况下,我想进行正则删除。用正则表