【发布时间】:2010-08-06 22:52:09
【问题描述】:
我有一张表 cats,有 42,795,120 行。
显然这是很多行。所以当我这样做时:
/* owner_cats is a many-to-many join table */
DELETE FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
查询超时:(
(编辑:我需要增加我的CommandTimeout值,默认只有30秒)
我不能使用TRUNCATE TABLE cats,因为我不想从其他主人那里吹走猫。
我正在使用 SQL Server 2005,并将“恢复模型”设置为“简单”。
所以,我想过做这样的事情(顺便说一句,从应用程序执行此 SQL):
DELETE TOP (25) PERCENT FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
DELETE TOP(50) PERCENT FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
DELETE FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
我的问题是:SQL Server 2005 中我可以DELETE 的行数阈值是多少?
或者,如果我的方法不是最优的,请提出更好的方法。谢谢。
这篇文章对我的帮助不够:
编辑(2010 年 8 月 6 日):
好的,我在再次阅读上面的链接后才意识到我在这些表上没有索引。此外,你们中的一些人已经在下面的 cmets 中指出了这个问题。请记住,这是一个虚构的架构,所以即使 id_cat 也不是 PK,因为在我的真实架构中,它不是一个唯一字段。
我会把索引放在:
cats.id_catowner_cats.id_catowner_cats.id_owner
我想我仍然掌握这个数据仓库的窍门,显然我需要所有 JOIN 字段的索引,对吧?
但是,我需要几个小时才能完成此批量加载过程。我已经以SqlBulkCopy 的身份进行操作(以块的形式,而不是一次全部 4200 万)。我有一些索引和 PK。我阅读了以下帖子,这些帖子证实了我的理论,即即使是批量复制,索引也会减慢速度:
- SqlBulkCopy slow as molasses
- What’s the fastest way to bulk insert a lot of data in SQL Server (C# client)
所以我要在复制之前DROP我的索引,然后在完成后重新CREATE它们。
由于加载时间较长,我需要一段时间来测试这些建议。我会报告结果。
更新(2010 年 8 月 7 日):
汤姆建议:
DELETE
FROM cats c
WHERE EXISTS (SELECT 1
FROM owner_cats o
WHERE o.id_cat = c.id_cat
AND o.id_owner = 1)
仍然没有索引,对于 4200 万行,它需要 13:21 分:秒,而上述方式需要 22:08。然而,对于 1300 万行,他用了 2:13 而不是我的老方法 2:10。这是个好主意,但我仍然需要使用索引!
更新(2010 年 8 月 8 日):
出了点大问题!现在打开索引,我上面的第一个删除查询花费了 1:9 hrs:min (是一个小时!),而 22:08 min:sec 和 13:21 min :sec 与 2:10 min:sec 分别用于 42 mil 行和 13 mil 行。我现在要尝试使用索引进行 Tom 的查询,但这是朝着错误的方向发展。请帮忙。
更新(2010 年 8 月 9 日):
Tom 的删除耗时 1:06 小时:分钟(42 百万行)和 10:50 分钟:秒(有索引的 13 百万行),而分别为 13:21 分钟:秒和 2:13 分钟:秒。 当我使用一个数量级的索引时,删除我的数据库所花费的时间更长!我想我知道为什么,我的数据库 .mdf 和 .ldf 从 3.5 GB 增长到 40.6 GB期间第一次(4200万)删除! 我做错了什么?
更新(2010 年 8 月 10 日):
由于没有任何其他选择,我想出了一个我觉得乏善可陈的解决方案(希望是暂时的):
- 将数据库连接超时时间增加到 1 小时(
CommandTimeout=60000;默认为 30 秒) - 使用 Tom 的查询:
DELETE FROM WHERE EXISTS (SELECT 1 ...),因为它的执行速度更快 -
DROP运行删除语句之前的所有索引和 PK (???) - 运行
DELETE语句 -
CREATE所有索引和 PK
看起来很疯狂,但至少它比使用 TRUNCATE 并从第一个 owner_id 开始加载我的负载要快,因为我的一个 owner_id 需要 2:30 hrs:min 来加载,而 17: 22 min:sec 用于我刚刚描述的 42 百万行的删除过程。 (注意:如果我的加载过程抛出异常,我会重新开始那个owner_id,但我不想吹走之前的owner_id,所以我不想TRUNCATEowner_cats 表,这就是我尝试使用DELETE的原因。)
我们将不胜感激:)
【问题讨论】:
-
你能解释一下你的表索引有什么吗?
-
我不是讨厌猫的人,但这不是很多行,而是很多猫 :) 而且,这让我很伤心“我不想把猫从其他人身上吹走业主”
-
这在 CrazyOldLady 数据库中吗?
-
owner_cats.id_cat、owner_cats.id_owner和cats.id_cat列上是否有索引?owner_cats.id_cat是主键吗? -
当您选择一个所有者时,如何删除行?听起来只有几行。这使得这些索引非常重要。我怀疑你可以在几秒钟内删除一个主人的猫。
标签: sql sql-server sql-delete correlated-subquery