我有一个SQL Server 2005数据库,我尝试在相应的字段上放置索引,以便从包含数百万行的表中加快DELETE
条记录(big_table
只有3列),但现在DELETE
执行时间甚至更长! (例如1小时对13分钟)
我与表之间存在关系,而我过滤DELETE
的列在另一个表中。例如
DELETE FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)
是的,我也尝试过:
DELETE FROM big_table
WHERE EXISTS
(SELECT 1 FROM small_table
WHERE small_table.id_product = big_table.id_product
AND small_table.id_category = 1)
虽然它看起来比第一次运行的速度略快,但索引的速度仍然比没有速度慢得多。
我在这些字段上创建了索引:
big_table.id_product
small_table.id_product
small_table.id_category
我的.ldf文件在DELETE
期间增长很多。
当我的表上有索引时,为什么我的DELETE
查询会变慢?我认为它们应该运行得更快。
更新
好的,共识似乎是索引会减慢巨大的DELETE
,因为索引必须更新。虽然,我仍然不明白为什么它不能同时DELETE
所有行,并且最后只更新一次索引。
我的一些阅读表明,通过更快地搜索DELETE
子句中的字段,索引会加快WHERE
。
“在DELETE和UPDATE命令中搜索记录时,索引也可以像在SELECT语句中一样工作。”
但是在文章后面,它说太多的索引会影响性能。
回答 bobs 问题:
SELECT
语句不会运行(抛出类型'System.OutOfMemoryException'的异常)我尝试了以下两个查询:
SELECT * FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)
SELECT * FROM big_table
INNER JOIN small_table
ON small_table.id_product = big_table.id_product
WHERE small_table.id_category = 1
运行 25分钟后, 失败,并出现来自SQL Server 2005的错误消息:
An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown.
数据库服务器是一台较旧的双核Xeon机器,内存为7.5 GB。这是我的玩具测试数据库:)所以它没有运行其他任何东西。
在我CREATE
之后我是否需要对我的索引做一些特别的事情才能让它们正常工作?
答案 0 :(得分:27)
索引使查找更快 - 就像书后面的索引一样。
更改数据的操作(如DELETE)速度较慢,因为它们涉及操纵索引。考虑本书后面的相同索引。如果添加,删除或更改页面,还有更多工作要做,因为您还必须更新索引。
答案 1 :(得分:2)
我同意上面的Bobs评论 - 如果您要从大型表中删除大量数据,删除索引可能需要一段时间才能删除数据,而不是开展业务的成本。因为它删除了所有数据,导致重建索引事件发生。
关于日志文件的增长;如果你没有对你的日志文件做任何事情,你可以切换到Simple日志记录;但我建议您在更改之前了解可能对您的IT部门产生的影响。
如果您需要实时删除;它通常是一个很好的工作,可以直接在表或另一个表中将数据标记为非活动状态,并从查询中排除该数据;然后再回来并在用户不盯着沙漏时删除数据。覆盖这个的第二个原因;如果要从表中删除大量数据(这是我根据您的日志文件问题所假设的),那么您可能希望使用indexdefrag来重新生成索引;如果您不喜欢手机上的用户,那就是在非工作时间内完成这项工作!
答案 2 :(得分:1)
JohnB正在删除大约75%的数据。我认为以下可能是一个可能的解决方案,可能是更快的解决方案之一。创建新表并插入需要保留的数据,而不是删除数据。插入数据后在该新表上创建索引。现在删除旧表并将新表重命名为旧表。
上述当然假设有足够的磁盘空间可用于临时存储重复数据。
答案 3 :(得分:0)
您还可以尝试使用TSQL扩展来删除语法,并检查它是否可以提高性能:
DELETE FROM big_table
FROM big_table AS b
INNER JOIN small_table AS s ON (s.id_product = b.id_product)
WHERE s.id_category =1
答案 4 :(得分:0)
尝试这样的操作以避免批量删除(从而避免日志文件增长)
declare @continue bit = 1
-- delete all ids not between starting and ending ids
while @continue = 1
begin
set @continue = 0
delete top (10000) u
from <tablename> u WITH (READPAST)
where <condition>
if @@ROWCOUNT > 0
set @continue = 1
end