最后是一个测试脚本,用于比较@table 变量和#temp 表之间的性能。我想我已经正确设置了 - 性能计时是在 DELETE/TRUNCATE 命令之外进行的。我得到的结果如下(以毫秒为单位)。
@Table Variable #Temp (delete) #Temp (truncate)
--------------- -------------- ----------------
5723 5180 5506
15636 14746 7800
14506 14300 5583
14030 15460 5386
16706 16186 5360
Run Code Online (Sandbox Code Playgroud)
只是为了确保我是理智的,这表明 CURRENT_TIMESTAMP (aka GetDate()) 是在语句时使用的,而不是批处理时,因此 TRUNCATE/DELETE 与SET @StartTime = CURRENT_TIMESTAMP语句之间不应有交互。
select current_timestamp
waitfor delay '00:00:04'
select current_timestamp
-----------------------
2012-10-21 11:29:20.290
-----------------------
2012-10-21 11:29:24.290
Run Code Online (Sandbox Code Playgroud)
当使用 DELETE 清除表时,第一次运行和后续运行之间的跳转非常一致。我对DELETE 的理解缺少什么?我已经重复了很多次,交换了顺序,调整了 tempdb 的大小以使其不需要增长等。
CREATE TABLE #values (
id int identity primary key, -- will be clustered …Run Code Online (Sandbox Code Playgroud) 我管理一个应用程序,它有一个非常大的(近 1TB 的数据,一个表中有超过 5 亿行)Oracle 数据库后端。数据库并没有真正做任何事情(没有 SProcs,没有触发器或任何东西)它只是一个数据存储。
每个月我们都需要从两个主表中清除记录。清除的标准各不相同,是行年龄和几个状态字段的组合。我们通常最终每月清除 10 到 5000 万行(我们每周通过导入增加大约 3 到 500 万行)。
目前我们必须分批进行大约 50,000 行的删除(即删除 50000、提交、删除 50000、提交、重复)。尝试一次删除整个批次会使数据库在大约一个小时内没有响应(取决于行数)。像这样批量删除行在系统上是非常粗糙的,我们通常必须“在时间允许的情况下”在一周内完成;允许脚本连续运行会导致用户无法接受的性能下降。
我认为这种批量删除也会降低索引性能,并有其他影响最终导致数据库性能下降。一张表就有34个索引,索引的数据量实际上比数据本身还大。
这是我们的一位 IT 人员用来执行此清除操作的脚本:
BEGIN
LOOP
delete FROM tbl_raw
where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;
exit when SQL%rowcount < 49999;
commit;
END LOOP;
commit;
END;
Run Code Online (Sandbox Code Playgroud)
该数据库必须达到 99.99999%,而且我们每年只有 2 天的维护窗口。
我正在寻找一种更好的方法来删除这些记录,但我还没有找到。有什么建议?
我需要跟踪已删除的项目以满足客户端同步需求。
一般来说,最好添加一个墓碑表和一个跟踪何时从服务器数据库中删除一行的触发器 - 基本上是将一个新行添加到带有已删除项目数据的墓碑表 - 或者将项目保留在原始表并将它们标记为已删除,通常带有一个类型为 bit 的列,以指示一行被删除,另一列在删除发生时进行跟踪?
认为这已通过以下链接解决 - 解决方法有效 - 但补丁没有。与 Microsoft 支持一起解决。
http://support.microsoft.com/kb/2606883
好的,所以我有一个问题,我想把它扔给 StackOverflow,看看是否有人有想法。
请注意,这是 SQL Server 2008 R2
问题:启用触发器时,从包含 15000 条记录的表中删除 3000 条记录需要 3-4 分钟,禁用触发器时只需 3-5 秒。
表设置
我们将称为 Main 和 Secondary 的两个表。Secondary 包含我要删除的项目记录,因此当我执行删除操作时,我会加入到 Secondary 表中。在删除语句之前运行一个进程,以使用要删除的记录填充辅助表。
删除声明:
DELETE FROM MAIN
WHERE ID IN (
SELECT Secondary.ValueInt1
FROM Secondary
WHERE SECONDARY.GUID = '9FFD2C8DD3864EA7B78DA22B2ED572D7'
);
Run Code Online (Sandbox Code Playgroud)
这个表有很多列和大约 14 个不同的 NC 索引。在我确定触发器是问题之前,我尝试了很多不同的事情。
触发器
该表有 3 个触发器(插入、更新和删除操作各一个)。我修改了删除触发器的代码以使其返回,然后选择一个以查看它被触发了多少次。它在整个操作过程中只触发一次(如预期的那样)。
ALTER TRIGGER [dbo].[TR_MAIN_RD] ON [dbo].[MAIN]
AFTER DELETE
AS
SELECT 1
RETURN
Run Code Online (Sandbox Code Playgroud)
回顾
我有一个表格,其中存储了用户在我网站上发布的所有论坛消息。消息层次结构是使用嵌套集模型实现的。
以下是该表的简化结构:
现在,该表看起来像这样:
+ ------- + ------------- + -------------- + ---------- + ----------- + ----------- +
| Id | Owner_Id | Parent_Id | nleft | nright | nlevel |
+ ------- + ------------- + -------------- + ---------- + ----------- + ----------- +
| 1 | 1 | NULL | 1 | 8 | 1 |
| 2 | 1 | 1 | 2 …Run Code Online (Sandbox Code Playgroud) 我正在使用 Microsoft SQL Server 2016 (SP2-CU11) (KB4527378) - 13.0.5598.27 (X64) Nov 27 2019 18:09:22 版权所有 (c) Windows Server 2012 R2 上的 Microsoft Corporation 标准版(64 位)标准 6.3(内部版本 9600:)
该服务器位于 SSD 驱动器上,最大内存为 128 GB。Parallelism 的 CostTheshold 是 70,MaxDegree of Parallelism 是 3。
我有一个“行程”表,它由 23 个外键引用,带有 ON DELETE CASCADE 选项。
这个表本身并没有那么大(530 万行,1.3 GB 数据)。但是在 23 个引用的表中,有两个表非常大(超过 10 亿行,每行 54 和 69 GB)。
问题是当我们尝试删除“Trips”表中的少量行(假设为 4 行)时,SQL 估计将要删除这么多行,它需要 10GB 的 RAM,估计将有数百万行返回,并锁定表。一切都停止,其他查询阻塞,应用程序超时。
以下是 1 个删除语句的主表和行数:
sql-server delete execution-plan sql-server-2016 query-performance
我有一个面试问题,这是我面试时问的。我回答了这个问题,但面试官对我的回答并不那么信服。所以,有人请用我的理解纠正我吗?
问:为什么 Truncate 是 DDL 而 Delete 是 DML?两者都做几乎相同的工作(删除行)
答。当我们使用 Truncate 时,我们正在取消分配由数据分配的整个空间,而不保存到撤消表空间中。但是,在删除的情况下,我们将所有数据放入撤消表空间,然后删除所有数据。
请,如果有人知道上述最佳答案,请解释。
在 SQL Server 2008 中,有一个主表,它通过一对多关系链接到其他三个子表。所以,我们想在主表中使用级联删除,这样当从主表中删除记录时,子表上的所有记录都会被删除。
我有一个非常频繁更新的表,其中包含 2.4 亿行(并且还在增长)。每三小时插入 150 万行,删除 150 万行。当我将集群移动到 SSD 时,批量插入(使用复制)时间从 22 分钟减少到 2.3 分钟。删除时间也得到改善。我计划每两小时或每小时进行一次批量更新。
虽然现在的性能(在 SSD 之后)与更频繁的更新兼容,但我读过一些关于 SSD 死亡的恐怖故事,因为 NAND 耐久性有限加上写放大。由于 SSD 价格昂贵,我想尽可能地将它的消亡推迟到未来。因此我的问题是:在删除和随后的真空中磁盘文件到底发生了什么?我猜有两个磁盘写入,一个将行标记为已删除,另一个在清理时将其标记为可覆盖。如果不是删除和清空,而是在每次批量插入/删除时对表进行分区创建和删除表,我会尽量减少 SSD 的磨损吗?
我有一个相当繁忙的 InnoDB 表(200,000 行,我猜大概每秒有几十个查询)。由于一个错误,我得到了 14 行(相同的)无效电子邮件地址,并想删除它们。
我只是尝试DELETE FROM table WHERE email='invalid address'并在大约 50 秒后得到“超出锁定等待超时”。这并不奇怪,因为行列没有编入索引。
但是,然后我做到了SELECT id FROM table WHERE email='invalid address',这花了 1.25 秒。运行DELETE FROM table WHERE id in (...),从 SELECT 结果中复制粘贴 id,花费了 0.02 秒。
到底是怎么回事?有人可以解释为什么带有条件的 DELETE 如此缓慢以至于超时,但是执行 SELECT 然后按 id 删除却如此之快?
谢谢。
编辑:根据要求,我发布了表结构以及一些explain结果。我还应该注意,没有引用此表的外键。
但是,情况对我来说似乎很简单:我选择了一个未编入索引的字段。这需要扫描整个表,但它并不是很大。id是主键,因此按 id 删除非常快,应该如此。
mysql> show create table ThreadNotification2 \G
*************************** 1. row ***************************
Table: ThreadNotification2
Create Table: CREATE TABLE `ThreadNotification2` (
`id` bigint(20) NOT …Run Code Online (Sandbox Code Playgroud) delete ×10
sql-server ×4
performance ×3
mysql ×2
oracle ×2
truncate ×2
constraint ×1
ddl ×1
foreign-key ×1
innodb ×1
oracle-11g ×1
partitioning ×1
postgresql ×1
storage ×1
trigger ×1
vacuum ×1