一些看似简单的数据操作,当作用于海量数据集时,就会出现“意料之外,却在情理之中”的问题,海量数据操作,需要采用特殊方法,才能“曲径通幽”。在删除海量数据时,需要注意日志的增长,索引碎片的增加和数据库的恢复模式,特别是利用大容量日志操作,来减少日志的增长和提高数据插入的速度。对于大数据去重,通过一些小小的改进,比如创建索引,设置忽略重复值选项等,能够提高去重的效率。

一,从海量数据中删除数据

从海量数据表中删除一半数据,看似简单,使用delete命令,如果真这么干,SQL Server产生的事务日志暴增,估计会把服务器硬盘爆掉。数据库的恢复模式会影响日志文件的增长,在删除海量数据时,根据采用的方法,相应地把恢复模式设置为simple,或bulk_logged 模式,能够在很大程度上减少删除操作产生的事务日志,从而避免日志暴增。

另外,在删除数据时,把表上的多余索引删除(注意,是删除多余的索引),只保留一个必需的索引;在数据删除完成之后,再重建索引,能够提高数据删除操作的性能。有人做过实验,从存储1.6亿条记录的大表中删除数据,每删除400万条要消耗1.5 - 3小时,越到后面速度越慢,为什么?这是因为,每次删除数据时,数据库都要相应地更新索引,这是很慢的硬盘 IO操作,并且,越到后面,索引碎片越多,更新索引就越慢,这就是在删除400万条记录时,一开始只消耗1.5小时,后面要消耗3小时原因。

最后,根据保留数据占总数据量的比例,选择不同的方法删除数据。如果大表中保留的数据较少,可以先把保留的数据存储到临时表中,然后,把原始表删除,这样能够利用大容量日志操作,来减少日志的增长和提高数据插入的速度。

1,循环删除,避免日志文件暴增

在从海量数据表中删除大量数据时,为了避免日志文件暴增,通常采用循环删除方法:首先设置恢复模式为simple,然后每次删除操作都只删除部分数据,这样,当单个删除操作执行完成时,事务日志会被及时清理,事务日志一般保持单个删除操作的事务日志量。

循环删除的伪代码如下,该方法仍有一些局限性,耗时过长,并且会长期使数据库处于简单恢复模式下:

--ALTER DATABASE database_name SET RECOVERY SIMPLE ;  

while @index<@EndIndex
begin
delete table_name
where index<=@index; set @index+=@Increment
end

2,将数据插入到临时表中,把原表drop

如果原始表有一半以上的数据要被删除,从原始表中执行delete命令删除数据,效率十分低下,可以考虑,把原始表中的数据通过select语句筛选出来,然后批量插入导新表中,这种方式利用了大容量日志(Bulk Logged)操作的优势。由于 SELECT INTO,INSERT SELECT 是大容量日志操作,select命令不会产生大量日志文件,因此,执行插入比执行删除的效率更高。最后,执行drop命令,删除整个原始表,几乎不消耗任何时间。

--ALTER DATABASE database_name SET RECOVERY BULK_LOGGED ;  

insert into new_table
select column_list
from original_table
where filter_retain drop table original_table

把临时表重命名,执行 sp_rename 或手动重命名,其中 @objtype 参数是可选的,默认值是NULL,对表重命名,设置参数 @objtype='object':

sp_rename [ @objname = ] 'object_name' , [ @newname = ] 'new_name'
[ , [ @objtype = ] 'object_type' ]

3,对分区表执行分区转移操作

SQL Server的分区表实际上是一系列物理上独立存储的“表”(也叫做分区)构成的,如果要删除的数据位于同一个分区,或者,一个分区中的数据都需要被删除,那么可以把该分区转移(switch)到一个临时表中,由于分区的转移仅仅是元数据库的变更,因此,不会产生任何的数据IO,分区转移瞬间完成。被剥离的分区,通过drop命令删除,整个过程仅仅会产生少量的IO操作,用于元数据变更;而不会产生用于数据删除的IO操作,这种方法,耗时最短,资源消耗最小,效率最高。

alter table original_table
SWITCH PARTITION source_partition_number
TO temporary_table drop table temporary_table

二,从海量数据中去重

数据去重,分为部分列去重和全部列去重,全部列去重,使用distinct子句来实现,由于distinct操作符会创建在tempdb中临时表,因此,distinct操作是IO密集型的操作。而部分列去重,一般采用row_number排名函数来实现,也可以考虑使用忽略重复值的唯一索引来实现。在实际的项目开发中,部分列去重更为常见。

1,使用row_number函数来实现

选择排名函数,是因为排名函数有部分列分区排序的功能:首先在部分列上创建索引,这样数据库引擎能够根据索引列快速排序,然后通过row_number函数和cte来实现重复数据的删除。在数据去重时,需要注意,如果删除的数据量太大,数据库引擎会产生大量的事务日志,导致日志文件暴增,在选择该方法时,需要慎重。

create index index_name
on table_name
(
index_columns
)
with(data_compression=page); with cte as
(
select index_columns,
row_number() over(partition by index_columns order by ...) as rn
from table_name
)
delete
from cte
where rn>1

2,使用忽略重复值的唯一索引来实现

通过插入和忽略重复值实现部分列的去重,相对来说,更容易控制,用户可以通过循环插入方式来执行,这样,在单独的一个事务中,控制插入数据的数量,能够控制产生的事务日志不至于太大,对于海量数据的去重,建议采用该方法。

创建一个临时表,在部分列上创建忽略重复值的唯一索引:

create unique index index_name
on new_table
(
index_columns
)
with(ignore_dup_key=on)

由于SQL Server不允许在包含重复值的数据表上创建唯一索引,因此,必须创建一个新的空表,新表时原始表的结构的复制,在部分列上创建忽略重复值的唯一索引。在执行插入操作时, IGNORE_DUP_KEY 选项会忽略重复的索引键值,并抛出警告(Warning)。

Go 作用的更多相关文章

  1. if __name__== "__main__" 的意思(作用)python代码复用

    if __name__== "__main__" 的意思(作用)python代码复用 转自:大步's Blog  http://www.dabu.info/if-__-name__ ...

  2. (转载)linux下各个文件夹的作用

    linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基 ...

  3. github中的watch、star、fork的作用

    [转自:http://www.jianshu.com/p/6c366b53ea41] 在每个 github 项目的右上角,都有三个按钮,分别是 watch.star.fork,但是有些刚开始使用 gi ...

  4. web.xml中welcome-file-list的作用

    今天尝试使用struts2+ urlrewrite+sitemesh部署项目,结果发现welcome-file-list中定义的欢迎页不起作用: <welcome-file-list> & ...

  5. web.xml中load-on-startup的作用

    如下一段配置,熟悉DWR的再熟悉不过了:<servlet>   <servlet-name>dwr-invoker</servlet-name>   <ser ...

  6. SQLSERVER中NULL位图的作用

    SQLSERVER中NULL位图的作用 首先感谢宋沄剑提供的文章和sqlskill网站:www.sqlskills.com,看下面文章之前请先看一下下面两篇文章 SQL Server误区30日谈-Da ...

  7. 电容与EMC-电容不同功能时对整板EMC的作用

    一般我们的pcb板的器件有很多种类,但是值得特别关注的,很多人都会说是BGA.接口.IC.晶振之类,因为这些都是layout功能模块以及设计难点.然而数量上占绝对优势的器件却是阻容器件,之前围殴阻抗时 ...

  8. FTP的搭建与虚拟目录作用<之简单讲解>

    操作系统:win7 VS2010编写WebService与在IIS的发布<之简单讲解>中我已经说了IIS安装与使用,不明白的可以跳过去看. 1.添加FTP站点 2. 3. 4. 5. zq ...

  9. 火狐浏览器中event不起作用解决办法--记录(一)

    今天遇到了这个问题.IE,谷歌下都没问题,但在FF下却不起作用,很郁闷查了半天,看别人博文写了老长,结果试了要么起作用,但太麻烦,要么不起作用,说了那么多跟没说一样. 其实只要这一句代码就行:e=ar ...

  10. scheduleInRunLoop作用

    例子一: - (void)setUpStreamForFile:(NSString *)path { // iStream is NSInputStream instance variable iSt ...

随机推荐

  1. elasticsearch-1.3.0 之索引代码粗略梳理

    elasticsearch-1.3.0 发送请求 创建 [root@centos ~]# curl -XPUT 172.16.136.159:9200/customer?pretty { " ...

  2. display:table-cell

    布局神器display:table-cell Author:owenhong2015-06-17 随着时间的推进,ie6.ie7在中国浏览器市场的占有率越来越低的情况,我现在工作的团队,经过用户访问数 ...

  3. 1. Activiti 运行时表信息总结

    Activiti的后台是有数据库的支持,所有的表都以ACT_开头. 第二部分是表示表的用途的两个字母标识. 用途也和服务的API对应. ACT_RE_*: 'RE'表示repository. 这个前缀 ...

  4. expect脚本语言用法示例

    #!/usr/bin/expect set hostname [lindex $argv 0] set username [lindex $argv 1] set passwd [lindex $ar ...

  5. struts2 框架处理流程

    struts2 框架处理流程 流程图如下: 注意:StrutsPrepareAndExecuteFilter替代了2.1.3以前的FilterDispatcher过滤器,使得在执行Action之前可以 ...

  6. SQLServer触发器创建、删除、修改、查看

    一: 触发器是一种特殊的存储过程﹐它不能被显式地调用﹐而是在往表中插入记录﹑更新记录或者删除记录时被自动地激活.所以触发器可以用来实现对表实施复杂的完整性约束. 二: SQL Server为每个触发器 ...

  7. 第一个独立开发的游戏 怪斯特:零 已经上线APP STORE!

    今天是个值得纪念的日子,而且是双喜临门 2年多来的摸爬滚打,终于有了回报 第一喜:自己独立开发的游戏 怪斯特:零 已经通过审核并上架APP STORE! 第二喜:迈入了自己期待2年之久的游戏行业,年后 ...

  8. 订单支付成功后存储过程 - MYSQL

    BEGIN SET @userId = (SELECT user_id FROM t_shoporder WHERE id = orderId); /*修改订单状态,改成已支付*/ ,update_t ...

  9. android——相对布局,表格布局

    1.相对布局 RelativeLayout 又称作相对布局,也是一种非常常用的布局.和LinearLayout 的排列规则不同,RelativeLayout 显得更加随意一些,它可以通过相对定位的方式 ...

  10. 华为oj 挑7

    #include<iostream> using namespace std; bool ishave_7(int n); int main(){ int num,k=0; cin> ...