AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 1750
Accepted
tuseau
tuseau
Asked: 2011-03-16 05:53:12 +0800 CST2011-03-16 05:53:12 +0800 CST 2011-03-16 05:53:12 +0800 CST

不使用子句加速巨大的 DELETE FROM <table> 的方法

  • 772

使用 SQL Server 2005。

我正在执行一个没有 where 子句的巨大 DELETE FROM。它基本上等同于 TRUNCATE TABLE 语句——除了我不允许使用 TRUNCATE。问题是表很大——有 1000 万行,需要一个多小时才能完成。有没有办法让它更快,没有:

  • 使用截断
  • 禁用或删除索引?

t-log 已经在单独的磁盘上。

欢迎任何建议!

sql-server performance
  • 5 5 个回答
  • 81436 Views

5 个回答

  • Voted
  1. Best Answer
    gbn
    2011-03-16T05:57:56+08:002011-03-16T05:57:56+08:00

    你可以做的是这样的批量删除:

    SELECT 'Starting' --sets @@ROWCOUNT
    WHILE @@ROWCOUNT <> 0
        DELETE TOP (xxx) MyTable
    

    例如,xxx 是 50000

    对此的修改,如果您想删除非常高百分比的行...

    SELECT col1, col2, ... INTO #Holdingtable
               FROM MyTable WHERE ..some condition..
    
    SELECT 'Starting' --sets @@ROWCOUNT
    WHILE @@ROWCOUNT <> 0
        DELETE TOP (xxx) MyTable WHERE ...
    
    INSERT MyTable (col1, col2, ...)
               SELECT col1, col2, ... FROM #Holdingtable
    
    • 41
  2. SQLRockstar
    2011-03-16T06:22:10+08:002011-03-16T06:22:10+08:00

    您可以使用 TOP 子句轻松完成此操作:

    WHILE (1=1)
    BEGIN
        DELETE TOP(1000) FROM table
        IF @@ROWCOUNT < 1 BREAK
    END
    
    • 22
  3. Jeff
    2011-03-19T08:13:23+08:002011-03-19T08:13:23+08:00

    如果您无法使用 TRUNCATE,我同意将您的删除批处理成可管理块的建议,并且我喜欢 drop/create 建议的独创性,但我对您问题中的以下评论感到好奇:

    它基本上等同于 TRUNCATE TABLE 语句 -除了我不允许使用 TRUNCATE

    我猜这个限制的原因与需要授予直接截断表的安全性有关,并且它允许您截断您所关心的表以外的表。

    假设是这种情况,我想知道创建一个使用 TRUNCATE TABLE 并使用“EXECUTE AS”的存储过程是否被认为是提供直接截断表所需的安全权限的可行替代方案。

    希望这将为您提供所需的速度,同时解决您的公司在将您的帐户添加到 db_ddladmin 角色时可能遇到的安全问题。

    以这种方式使用存储过程的另一个优点是存储过程本身可以被锁定,以便只允许特定帐户使用它。

    如果由于某种原因这不是一个可接受的解决方案,并且您需要删除此表中的数据是需要每天/每小时/等执行一次的事情,我会要求创建一个 SQL 代理作业来截断表在每天的预定时间。

    希望这可以帮助!

    • 7
  4. Marian
    2011-03-16T07:44:22+08:002011-03-16T07:44:22+08:00

    除了截断..只有批量删除可以帮助你。

    当然,您可以删除该表并使用所有约束和索引重新创建它。在 Management Studio 中,您可以选择编写要删除和创建的表的脚本,因此它应该是一个简单的选项。但这只有在您被允许执行 DDL 操作时才这样做,我认为这不是一个真正的选择。

    • 5
  5. Max xaM
    2018-12-05T14:19:51+08:002018-12-05T14:19:51+08:00

    由于这个问题是如此重要的参考,我发布了这段代码,它真正帮助我理解了循环删除以及循环内的消息传递以跟踪进度。

    查询是根据这个重复的问题修改的。感谢@RLF查询库。

    CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
    INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
    SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
    go
    DECLARE @HowMany INT;
    DECLARE @RowsTouched INT;
    DECLARE @TotalRowCount INT;
    DECLARE @msg VARCHAR(100);
    DECLARE @starttime DATETIME 
    DECLARE @currenttime DATETIME 
    
    SET @RowsTouched = 1; -- Needs to be >0 for loop to start
    SET @TotalRowCount=0  -- Total rows deleted so far is 0
    SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
    SET @starttime=GETDATE()
    
    WHILE @RowsTouched > 0
    BEGIN
       DELETE TOP (@HowMany)
       FROM #DelTest 
       WHERE name LIKE '%sys%';
    
       SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
       SET @TotalRowCount = @TotalRowCount+@RowsTouched; -- Increment Total rows deleted count
       SET @currenttime = GETDATE();
       SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
       RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  
    
    END; 
    SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
    DROP TABLE #DelTest;
    
    • 3

相关问题

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    您如何显示在 Oracle 数据库上执行的 SQL?

    • 2 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    我可以查看在 SQL Server 数据库上运行的历史查询吗?

    • 6 个回答
  • Marko Smith

    如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

    • 10 个回答
  • Marko Smith

    如何在 Mac OS X 上运行 psql?

    • 11 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Marko Smith

    将数组参数传递给存储过程

    • 12 个回答
  • Martin Hope
    Manuel Leduc PostgreSQL 多列唯一约束和 NULL 值 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler 什么时候应该将主键声明为非聚集的? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - 哪个更好作为主键? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick 如何优化大型数据库的 mysqldump? 2011-01-04 13:13:48 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve