惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 热门话题
C
Check Point Blog
Hugging Face - Blog
Hugging Face - Blog
N
News | PayPal Newsroom
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Troy Hunt's Blog
H
Heimdal Security Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Secure Thoughts
博客园 - Franky
A
Arctic Wolf
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
T
Threat Research - Cisco Blogs
The Last Watchdog
The Last Watchdog
博客园_首页
Forbes - Security
Forbes - Security
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
T
Threatpost
Y
Y Combinator Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
小众软件
小众软件
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Schneier on Security
Schneier on Security
博客园 - 叶小钗
量子位
Security Latest
Security Latest
酷 壳 – CoolShell
酷 壳 – CoolShell
U
Unit 42
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 聂微东
Apple Machine Learning Research
Apple Machine Learning Research
Jina AI
Jina AI
P
Privacy International News Feed
Help Net Security
Help Net Security
博客园 - 司徒正美
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
C
CERT Recently Published Vulnerability Notes
T
The Exploit Database - CXSecurity.com

博客园 - 谢堂文(Darren Xie)

Camstar MES 5.8 發現Ajax事件失效 验证(C#和正则表达式) 新MES已上線 Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine Microsoft SQL Server Reporting Services (SSRS)报表技巧之在图表中增加参考线 MS SQL,数据库增长时众多表中谁是你关注的目标 SQL调优日记之发挥SQL性能与你的写法有关--对比三种方式实现相同功能 想个法子找出性能差的SQL T-SQL 日期处理总结 一步一步用C#写一个检查SQL Server假死警报服务 MM的Windows 7 登录密码忘记之后 基于工作实际需求的Ext.Net和C#搭配应用之一 取出网域(AD)中所有计算机名及位置描述等信息 MS SQL自定义字符串拆分函数的惨痛经历 2012,我的C#全能Excel操作(无需Office,不使用XML) 代码注释规范 2012年开发者该做的11件事 取出AD中一個組的所有成員信息(C#實現功能配合EXT做的界面) 一個文件文件和路徑的類 C#路径/文件/目录/I/O常见操作汇总
从MS SQL删除大数据说开去
谢堂文(Darren Xie) · 2012-03-30 · via 博客园 - 谢堂文(Darren Xie)

对于数据库中删除数据,你说要注意什么呢?代码怎样写?

多数同学看到这两个问题,想都不想就说,就一个Delete语句,注意删除的条件不要删除错了就是,有什么好注意的!

是的,可以我再问一下,删除动作是会写日志的,你放日志的磁盘够空间吗?

本文的内容:

1. 我先举个实际的工作问题;

2. 整理T-SQL的删除数据的语句和写法;

3. 解决这个工作中的问题和效果总结。

先举个我实际工作中的事例,我们在这样的一个应用,每天定时收集一些数据写入数据库中,数据库中有一批表(十几个)存放这些数据,由于数据量很大,三个月的单表数据在1亿以上,所以,我们只用表保存90天的数据,用于做什么我们在这里不关心好不好。在每天都有一个Job去删除90天以前的数据。由于这是很早前,我的前辈所做的,现在人已不在这公司了。这些表所有的动作就以下的语句来删除:

   1:  DELETE FROM dbo.S5_BinTest_Detail 
   2:         where BinTestID in (SELECT BinTestID 
   3:             from dbo.S5_BinTest_Info 
   4:             where TS <dateadd(dd,-90,getdate())
   5:         )
   6:         and datediff(dd,(select min(TS) from S5_BinTest_Info),TS)<=0
   7:         
   8:   DELETE from dbo.S5_BinTest_Info where TS <dateadd(dd,-90,getdate())
   9:         and datediff(dd,(select min(TS) from S5_BinTest_Info),TS)<=0

这只是一次只删除一天的数据,也就是日期最早的,90天以前的。昨晚就收到了以下的服务器报警:

image

我看到平时服务器上各磁盘的空间使用情况如下,D盘是日志文件所在的盘,平时大概有95G的可用空间;

E盘是数据文件存放的盘,平时有170G的可用空间。由于数据每天的新增和删除的量都基本平衡,所以也就没有多大的变化。

image

现在看到数据库文件已有121G这么大。多个亿级别的表了。

image

平时的日志文件几百M。

image

这报警是D盘小于40G,那就是说日志文件增长了45G以上,那时也正好是删除数据的Job在执行。在我检查这些删除动作的语句时,发现了问题,就是没有考虑删除大数据时日志增长与磁盘空间的关系。这样下去,可能那一次就挂了。

再说说删除数据的方式:

对于删除数据,T-SQL提供了两个从表中删除数据行的语句:Delete和TRUNCATE.

DELETE 语句是标准的SQL语句,它用于根据指定的谓词(条件)从表中删除数据。这个标准的语句只有两个子句:用于指定目标表名的FROM子句和用于指定谓调整条件的WHERE子句。只有能让谓词条件计算结果为TRUE的行才会被删除。

例如:

DELETE from dbo.S5_BinTest_Info where TS <dateadd(dd,-90,getdate());

这是删除表S5_BinTest_Info中时间字段TS早于90天的数据。

DELETE语句采用的是完整模式的日志处理,当删除大量数据时,可能会花费大量的时间还有需要大量的日志存放空间。

TRUNCATE语句不是标准的SQL语句,它用于删除表中所有的行。与DELETE语句不同,TRUNCATE不需要加条件,如:

TRUNCATE TABLE dbo.S5_BinTest_Info;

和DELETE语句相比,TRUNCATE具有以最小模式记录日志和优点。和DELETE语句的完整模式在性能上有巨大的差异。TRUNCATE的速度最快。当表中有标识列时,DELETE不会改变标识列的值,TRUNCATE则会重置为最初的种子值。

再说说基于联接的DELETE,T-SQL支持一种基于联接的DELETE语法,这不是一种标准的SQL语法。联接本身就有过虑的作用,因为它有一个基于谓词的过滤器(ON子句)。通过联接可以访问另一个表中相关行的属性(列),并在WHERE子句中引用这些属性,这就意味着可以根据对另一个表中相关行的属性定义的过虑器来删除表中的数据行。例如:

DELETE FROM S5

        FROM dbo.S5_BinTest_Info AS S5

        JOIN dbo.S5_BinTest_Info_Dtl AS DTL

       ON S5.ID=DTL.ID

       WHERE DTL.QTY=1;

这和SELECT语句非常相似,DELETE语句在逻辑上第一个处理的子句是FROM子句(第二行FROM dbo.S5_BinTest_Info AS S5的这个),接着处理WHERE子句,最后才是DELETE子句。

这也可以用查询子句来实现同样的处理:

DELETE FROM dbo.S5_BinTest_Info

       WHERE EXISTS(SELECT 1 FROM dbo.S5_BinTest_Info_Dtl AS DTL

                WHERE S5_BinTest_Info .ID=DTL.ID AND DTL.QTY=1);

这里的查询子句的方式是标准的SQL语句,我更喜欢使用标准SQL。

再回到我这个工作中的问题,我想用分批删除的方式来处理。一次删除合理数据的记录,多删除几次就可以了。

由于我为里是有ID的,所以一次删除一个ID号的记录,以下是更改后的循环方式实现源码。

   1:  --2012-03-30,因删除大数据问题,以下更改为分批删除的方式实现
   2:      DECLARE @MINID INT;
   3:      DECLARE @N INT;
   4:      --取出要删除的90天前的记录的ID
   5:      SELECT BinTestID into #S5ID
   6:                from dbo.S5_BinTest_Info 
   7:                where TS <dateadd(dd,-90,getdate());
   8:      --以要删除的ID数量为循环变量,因为ID号可能不连续
   9:      SELECT @N=(SELECT COUNT(1) FROM #S5ID);
  10:      WHILE (@N>0)
  11:      BEGIN
  12:         -- 一次删除一个ID对应的数据
  13:         SELECT @MINID=MIN(BinTestID) FROM #S5ID;
  14:         DELETE FROM dbo.S5_BinTest_Detail 
  15:             where BinTestID=@MINID;
  16:         DELETE from dbo.S5_BinTest_Info 
  17:             where BinTestID=@MINID;
  18:         --从临时表中去除已删除的ID号
  19:         DELETE #S5ID WHERE BinTestID=@MINID;
  20:         --更改剩余要删除的ID数,这是循环变量
  21:         SELECT @N=(SELECT COUNT(1) FROM #S5ID);
  22:      END
  23:      DROP TABLE #S5ID;

如果对于没有ID的数据表,我们可以用TOP的方式来删除。

我使用这样的方式执行时,日志基本没有增长,因为删除一次很少的数据,成功后会释放,再使用。

您,删除数据时考虑语法和条件还有大量数据的日志增长空间问题了吗?

原创文章,请转载请注明出处。