SQL Server大表如何快速删除数据「终于解决」

SQL Server大表如何快速删除数据「终于解决」在SQL Server中,如何快速删除大表中的数据呢? 回答这个问题前,我们必须弄清楚上下文环境和以及结合实际、具体的需求,不同场景有不同的应对方法。 1: 整张表的数据全部删除 如果是整张表的数据全

SQL Server大表如何快速删除数据

 

在SQL Server中,如何快速删除大表中的数据呢?  回答这个问题前,我们必须弄清楚上下文环境和以及结合实际、具体的需求,不同场景有不同的应对方法。

 

 

1: 整张表的数据全部删除

 

 

如果是整张表的数据全部清空、删除,这种场景倒是非常简单,TRUNCATE TABLE肯定是最快的。 反而用DELETE处理的话,就是一个糟糕的策略。

 

 

2: 大表中删除一部分数据

 

 

对于场景1、非常简单,但是很多实际业务场景,并不能使用TRUNCATE这种方法,实际情况可能只是删除表中的一部分数据或者进行数据归档后的删除。假设我们遇到的表为TEST,需要删除TEST表中的部分数据。那么首先我们需要对表的数据量和被删除的数据量做一个汇总统计,具体,我们应该采用下面方法:

 

·           检查表的数据量,以及要删除的数据量。然后计算删除的比例,

 

    sp_spaceused “dbo.TEST”;

 

    SELECT COUNT(*) AS DELETE_RCD WHERE TEST WHERE ……<删除条件>

 

 

2.1 删除大表中绝大部分的数据,但是这个绝大部分怎么定义不好量化,所以我们这里就量化为60%。如果删除的数据比例超过60%,就采用下面方法:

 

1: 新建表TEST_TMP

 

2:  将要保留的数据转移到TEST_TMP

 

3: 将原表TEST重命名为TEST_OLD, 而将TEST_TMP重命名为TEST

 

4: 检查相关的触发器、约束,进行触发器或约束的重命名

 

5: 核对操作是否正确后,原表(TEST_OLD)要么TRUANCATE后,再DROP掉。要么保留一段时间,保险起见。

 

注:至于这个比例60%是怎么来的。这个完全是个经验值,有简单的测试,但是没有很精确和科学的概率统计验证。

 

 

另外,还要考虑业务情况,如果一直有应用程序访问这个表,其实这种方式也是比较麻烦的,因为涉及数据的一致性,业务中断等等很多情况。但是,如果程序较少访问,或者在某个时间段没有访问,那么完全可以采用这种方法。

 

 

2.2 删除大表中部分数据,如果比例不超过60%

 

 

1:先删除或禁用无关索引(无关索引,这里指执行计划不用到的索引,这里是指对当前DELETE语句无用的索引)。因为DELETE操作属于DML操作,而且大表的索引一般也非常大,大量DELETE将会对索引进行维护操作,产生大量额外的IO操作。

 

2:用小批量,分批次删除(批量删除比一次性删除性能要快很多)。不要一次性删除大量数据。一次性删除大量记录。会导致锁的粒度范围很大,并且锁定的时间非常长,而且还可能产生阻塞,严重影响业务等等。而且数据库的事务日志变得非常大。执行的时间变得超长,性能非常糟糕。

 

批量删除时,到底一次性删除多少数量的记录数,SQL效率最高呢?  这个真没有什么规则计算,个人测试对比过,一次删除10000或100000,没有发现什么特别规律。(有些你发现的规律,换个案例,发现不一样的结果,这个跟环境有关,有时候可能是一个经验值)。不过一般用10000,在实际操作过程,个人建议可以通过做几次实验对比后,选择一个合适的值即可。

 

案例1:

 

DECLARE @delete_rows INT;

代码100分

代码100分DECLARE @delete_sum_rows INT =0;

DECLARE @row_count INT=100000

代码100分 

WHILE 1 = 1

    BEGIN

        DELETE TOP ( @row_count )

        FROM    dbo.[EmployeeDayData]

        WHERE    WorkDate < CONVERT(DATETIME, "2012-01-01 00:00:00",120);

            

        SELECT  @delete_rows = @@ROWCOUNT;

            

            SET @delete_sum_rows +=@delete_rows

            IF @delete_rows = 0

            BREAK;

        END;

SELECT @delete_sum_rows;

 

 

 

案例2:

 

DECLARE @r INT;

DECLARE @Delete_ROWS  BIGINT;

 

SET @r = 1;

SET @Delete_ROWS =0

WHILE @r > 0

BEGIN

    BEGIN TRANSACTION;

        DELETE TOP (10000) -- this will change

           YourSQLDba..YdYarnMatch

           WHERE Remark="今日未入" and Operation_Date<CONVERT(datetime, "2019-05-30",120);

 

          SET @r = @@ROWCOUNT;

          

          SET @Delete_ROWS += @r;

 

    COMMIT TRANSACTION;

    

    PRINT(@Delete_ROWS);

 

END

 

 

该表有下面两个索引

 

USE [YourSQLDba]

GO

 

 

IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N"[dbo].[YdYarnMatch]") AND name = N"IX_YdYarnMatch_N2")

DROP INDEX [IX_YdYarnMatch_N2] ON [dbo].[YdYarnMatch] WITH ( ONLINE = OFF )

GO

 

USE [YourSQLDba]

GO

 

 

CREATE NONCLUSTERED INDEX [IX_YdYarnMatch_N2] ON [dbo].[YdYarnMatch] 

(

    [Job_No] ASC,

    [GK_No] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]

GO

 

USE [YourSQLDba]

GO

 

IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N"[dbo].[YdYarnMatch]") AND name = N"IX_YdYarnMatch_N1")

DROP INDEX [IX_YdYarnMatch_N1] ON [dbo].[YdYarnMatch] WITH ( ONLINE = OFF )

GO

 

USE [YourSQLDba]

GO

 

CREATE NONCLUSTERED INDEX [IX_YdYarnMatch_N1] ON [dbo].[YdYarnMatch] 

(

    [Operation_Date] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]

GO

 

 

重点:实践证明,如果新建一个索引,能够避免批量删除过程中执行计划走全表扫描,也能大大加快删除的速度。个人对这个案例进行了测试、验证。发现加上合适索引后,让DELETE语句走Index Seek后,删除效率确实大大提升。

 

 

删除索引IX_YdYarnMatch_N2,保留索引IX_YdYarnMatch_N1,但是发现SQL执行计划走全表扫描,执行SQL时,删除非常慢

 

clip_image001

 

删除索引IX_YdYarnMatch_N1,重新创建索引IX_YdYarnMatch_N1后,执行计划走Index Seek,删除效率大大提示。

 

CREATE NONCLUSTERED INDEX [IX_YdYarnMatch_N1] ON [dbo].[YdYarnMatch]

(

    [Operation_Date] ASC ,

    Remark

   

)

 

注意:此处索引名相同,但是索引对应的字段不一样。

 

clip_image002

 

 

所以正确的做法是:

 

1:先删除或禁用无关索引(对当前DELETE语句无用的索引),删除前生成对应的SQL,以便完成数据删除后,重新创建索引。注意,前提是在操作阶段,这个操作不会影响应用。否则应重新考虑。

 

2:检查测试当前SQL的执行计划,能否创建合适的索引,加快DELETE操作。如上面例子所示

 

3:批量循环删除记录。

 

4:在ORACLE数据库中,有些表的设置可以减少对应DML操作的日志生成量,但是SQL Server没有这些功能,但是要及时关注或调整事务日志的备份情况。

 

    如果我们能将将数据库的恢复模式设置为SIMPLE,那么可以减少日志备份引起的额外的IO开销。但是很多生产环境不能切换用户数据库的恢复模式。

 

 

其实说了这么多,SQL Server中大表快速删除索引的方法就是将一次性删除改成分批删除,逐次提交而已。其它的方式都是一些辅助方式而已。另外,如果你想亲自做一些细节测试,建议参考博客https://sqlperformance.com/2013/03/io-subsystem/chunk-deletes

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/9647.html

(0)
上一篇 2023-02-03
下一篇 2023-02-04

相关推荐

  • Python字符串.startswith的使用方法

    Python字符串.startswith的使用方法Python是一种高级编程语言,提供了丰富的字符串操作函数。其中startswith是Python中比较常用的一个字符串函数之一。startswith函数用于判断字符串是否以指定的子串开头,返回布尔值True或False。函数的语法格式如下:

    2024-01-08
    66
  • 【原创】强撸基于 .NET 的 Redis Cluster 集群访问组件

    【原创】强撸基于 .NET 的 Redis Cluster 集群访问组件Hello 大家好,我是TANZAME,我们又见面了。今天我们来聊聊怎么手撸一个 Redis Cluster 集群客户端,纯手工有干货,您细品。 随着业务增长,线上环境的QPS暴增,自然而然

    2023-03-13
    108
  • mac 安装 navicat for mysql 直接安装

    mac 安装 navicat for mysql 直接安装mac 安装 navicat for mysql 直接安装
    首先打开mac控制台输入命令行:sudo spctl –master-disable
    百度盘,提取码: vrtr
    失效请留言,会及时更新,

    2023-01-22
    112
  • [学习笔记] Oracle基础增删改查用法「终于解决」

    [学习笔记] Oracle基础增删改查用法「终于解决」查询 备份查询数据 插入 插入查询结果 更新 通过查询结果更新 删除 截断表 删除和截断的区别 TRUNCATE 是 DDL 命令,命令执行完就提交,删除的数据不能恢复; DELETE 命令是 DML

    2023-02-03
    105
  • Apache Solr入门教程(初学者之旅)「建议收藏」

    Apache Solr入门教程(初学者之旅)「建议收藏」作者 | 胡海超的博客 来源 | https://blog.csdn.net/u011936655/article/details/51960005 写在前面:本文涉及solr入门的各方面,请逐行阅…

    2022-12-16
    106
  • Redis入门(3) – 事务和缓存

    Redis入门(3) – 事务和缓存事务的使用方式 事务的错误处理 WATCH命令 生存时间 缓存策略 Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执…

    2023-03-04
    102
  • apache 大数据_hadoop开发教程

    apache 大数据_hadoop开发教程一、Azkaban API概述 通常,企业里一般不用使用web UI去设置或者执行任务,只是单纯的在页面上查看任务或者排查问题,更多的是通过Azkaban API去提交执行任务计划。Azkaban提供

    2023-05-17
    97
  • MySQL之架构简单分析

    MySQL之架构简单分析上图为MySQL的简易架构图,给您有一个大概的概念,下面我将为您进行进一步的分析。 连接器: 当连接MySQL数据库时,等待的将是MySQL服务端的连接器;连接器的职责是和客户端建立连接、获取权限、维

    2022-12-17
    102

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注