Sql数据量不变的情况下..数据文件mdf大幅度增加.. http://bbs.csdn.net/topics/392089229
在早上的帖子中..最终的结论推测可能是字段和索引重复建立造成的数据库文件虚增..
所以去写了一段代码来专门测试是否是这个问题..
//事先在表中添加了265w行数据.. 只有一列 MemberNumber
int INDEX = 0;
while (INDEX < 10)
{
int cou = 15;
for (int i = 0; i < cou; i++)
{
var ItemField = "value" + i;
Console.WriteLine("======检查索引,并删除=====value" + i);
David.DB.DoSQL.Ext_DropIndex(TargetTable, string.Format("INDEX_{0}_{1}", TargetTable, ItemField).ToUpper());
Console.WriteLine("======删除列重建=====value" + i);
bool IsSeccessAddCol = David.DB.DoSQL.Ext_InitColumn(TargetTable, ItemField, David.Common.ComEnum.OverAll.ExcDataType.整数, "", "0");
Console.WriteLine("======开始覆盖数据=====value" + i);
SQL_Sync = "UPDATE " + TargetTable + " SET " + ItemField + "=100";
sync_Result = David.DB.DoSQL.ExecuteRowCount(SQL_Sync);
Console.WriteLine("修改 [" + sync_Result + "] 行数据");
Console.WriteLine("======创建索引=====value" + i);
David.DB.DoSQL.Ext_CreateIndex(TargetTable, string.Format("INDEX_{0}_{1}", TargetTable, ItemField).ToUpper(), ItemField);
Console.WriteLine("创建索引完成");
}
//在来一次
INDEX++;
}
思路是这样..
1. 一张空表..有一个字段MemberNumber..添加入265w数据..给该字段建立聚集索引..
2. 然后双循环嵌套..
2.1 内层执行顺序是 删索引 -> 重建字段 -> 每行都赋值为10 -> 建立索引 这样建立15个字段和15个索引
2.2 外层循环把内层的整个过程执行10次..每次在 Index++ 的时候..看一下库的Mdf文件的大小..
实际执行时只跑了四圈就很明显的看出问题了..
值分别如下..:
2155.00 M
2327.00 M
2498.00 M
2671.00 M..
记录时数据库都没有什么空闲值..基本100%占用..
每次都有171M左右的增加..
这就奇怪了.. 字段数量没有增加..索引数量没有增加..字段的内容没有改变..为什么会多出这171M..
请高手解答..
16 个解决方案
#1
你看看你的数据库每次增长多少,一般是按照原大小的半分比,或者是一个固定的大小来增长的
#2
每次171M左右..
#3
呃..可能有个误会..我指的并不是数据库的自然增长..
如果数据有增加..比如原来有100行现在变为2000行..那数据文件增长是正常的..
但是现在问题是数据内容没有改变..只是重新计算..数据文件也会增长..
增长了171M占用仍然是100%.. 等于白白多出了171M的占用..
我是想知道这是什么东西..
#4
正常啊。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
#5
呃..表示不赞同..
如果按您的理解的话..那一个库如果使用事务较多..那岂不要产生极多的硬盘占用..并且是无意义的..
另外我这个demo里没有使用事务提交..
#6
事务提交前保留一份数据做为回滚的依据我是赞同的..但如果说提交后依然留有备份..则不赞同..
#7
昨天回去路上就想到了,我把回滚用数据和日志用数据搞混了。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
#8
昨天回去路上就想到了,我把回滚用数据和日志用数据搞混了。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
对..其实现在的重心在数据文件 mdf上..
日志的话现在是简单模式,定时维护计划有收缩..不然一天能跑300G+的日志..再大也能跑..因为磁盘剩余空间就300G了..
我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放.. 故每次增加171M..虽然前后两次建立的列名一样..但是其实地址或者指针什么的不一样了..之前的列变成了无名数据..却一直占用空间..
只是猜测..有大神看到了请指正..
#9
碎片也不多..
下边是碎片扫描的结果..
最优和实际之间的差距很小..
但每页可用字节数有点高..
下边是碎片扫描的结果..
最优和实际之间的差距很小..
但每页可用字节数有点高..
#10
收缩一下日志文件吧
#11
这个不知道是不是数据库的问题?
#12
我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放
本来就应该这样的。删列只需要把定义标记为不用,并不会对数据进行处理,数据库总是时间优先。
你可以对每步操作测下时间,删列应该是很快的。
#13
[Quote=引用 9 楼 sunyanjie_china 的回复:]我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放
本来就应该这样的。删列只需要把定义标记为不用,并不会对数据进行处理,数据库总是时间优先。
你可以对每步操作测下时间,删列应该是很快的。
对的..我其实只是想在重新计算前..把原有数据初始化掉..当时使用 Update set col=null 速度太慢.. 改用了直接删列重建..
我把方法改回来了..正在测试数据库是否会变大.. 目前来看是正常的..
#14
几百万数据都要重算,有这样的需求?
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
#15
几百万数据都要重算,有这样的需求?
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
用户标签的计算.. 几百万是用户.. 每个用户的各种属性和指标..在一定期限后要重新计算..譬如生命周期.. 最近28天的消费和互动指数..
因为要求web端实时的能够任意组合标签和属性来得到交集用户.. 所以使用hive端计算..sql端更新和存储..
设计应该是没问题的.. 当然有大神觉得有更好方案的不妨交流一下..
#16
全体清零,一次性操作的数据太多,事务就大了。
只对有需要的用户重新计算。
比如“最近28天的消费和互动指数”的用户ID挑出来加到一个临时表,还有其它的相关业务的用户ID也挑出来加到临时表……
最好依据临时表内的用户ID分批对用户重新计算。
只对有需要的用户重新计算。
比如“最近28天的消费和互动指数”的用户ID挑出来加到一个临时表,还有其它的相关业务的用户ID也挑出来加到临时表……
最好依据临时表内的用户ID分批对用户重新计算。
#1
你看看你的数据库每次增长多少,一般是按照原大小的半分比,或者是一个固定的大小来增长的
#2
你看看你的数据库每次增长多少,一般是按照原大小的半分比,或者是一个固定的大小来增长的
每次171M左右..
#3
你看看你的数据库每次增长多少,一般是按照原大小的半分比,或者是一个固定的大小来增长的
呃..可能有个误会..我指的并不是数据库的自然增长..
如果数据有增加..比如原来有100行现在变为2000行..那数据文件增长是正常的..
但是现在问题是数据内容没有改变..只是重新计算..数据文件也会增长..
增长了171M占用仍然是100%.. 等于白白多出了171M的占用..
我是想知道这是什么东西..
#4
正常啊。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
#5
正常啊。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
呃..表示不赞同..
如果按您的理解的话..那一个库如果使用事务较多..那岂不要产生极多的硬盘占用..并且是无意义的..
另外我这个demo里没有使用事务提交..
#6
正常啊。
记录更新时会把旧数据复制一份,在事务递交前作为回滚的依据,事务递交后一样要留着,作为事务备份/事务复制的依据。
既然你265w数据全体更新,就会有固定大小的旧数据复制保存。
你试试每次执行后截断事务。
呃..表示不赞同..
如果按您的理解的话..那一个库如果使用事务较多..那岂不要产生极多的硬盘占用..并且是无意义的..
另外我这个demo里没有使用事务提交..
事务提交前保留一份数据做为回滚的依据我是赞同的..但如果说提交后依然留有备份..则不赞同..
#7
昨天回去路上就想到了,我把回滚用数据和日志用数据搞混了。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
#8
昨天回去路上就想到了,我把回滚用数据和日志用数据搞混了。
更新时有两份副本:
一份旧数据,用于事务回滚,事务结束则丢弃。
一份新数据,用于备份/复制,会一直保留到截断事务时。
因为用事务备份恢复时,旧数据数据库中有,但是这个操作将要更新的新数据需要从备份中取。
对..其实现在的重心在数据文件 mdf上..
日志的话现在是简单模式,定时维护计划有收缩..不然一天能跑300G+的日志..再大也能跑..因为磁盘剩余空间就300G了..
我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放.. 故每次增加171M..虽然前后两次建立的列名一样..但是其实地址或者指针什么的不一样了..之前的列变成了无名数据..却一直占用空间..
只是猜测..有大神看到了请指正..
#9
碎片也不多..
下边是碎片扫描的结果..
最优和实际之间的差距很小..
但每页可用字节数有点高..
下边是碎片扫描的结果..
最优和实际之间的差距很小..
但每页可用字节数有点高..
#10
收缩一下日志文件吧
#11
这个不知道是不是数据库的问题?
#12
我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放
本来就应该这样的。删列只需要把定义标记为不用,并不会对数据进行处理,数据库总是时间优先。
你可以对每步操作测下时间,删列应该是很快的。
#13
[Quote=引用 9 楼 sunyanjie_china 的回复:]我觉得有可能是在删除重建列之后..原本的列占用的空间并没有释放
本来就应该这样的。删列只需要把定义标记为不用,并不会对数据进行处理,数据库总是时间优先。
你可以对每步操作测下时间,删列应该是很快的。
对的..我其实只是想在重新计算前..把原有数据初始化掉..当时使用 Update set col=null 速度太慢.. 改用了直接删列重建..
我把方法改回来了..正在测试数据库是否会变大.. 目前来看是正常的..
#14
几百万数据都要重算,有这样的需求?
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
#15
几百万数据都要重算,有这样的需求?
设计没问题吧?通常是只有按照时间相关或有业务发生相关的一批数据才需要重算。
用户标签的计算.. 几百万是用户.. 每个用户的各种属性和指标..在一定期限后要重新计算..譬如生命周期.. 最近28天的消费和互动指数..
因为要求web端实时的能够任意组合标签和属性来得到交集用户.. 所以使用hive端计算..sql端更新和存储..
设计应该是没问题的.. 当然有大神觉得有更好方案的不妨交流一下..
#16
全体清零,一次性操作的数据太多,事务就大了。
只对有需要的用户重新计算。
比如“最近28天的消费和互动指数”的用户ID挑出来加到一个临时表,还有其它的相关业务的用户ID也挑出来加到临时表……
最好依据临时表内的用户ID分批对用户重新计算。
只对有需要的用户重新计算。
比如“最近28天的消费和互动指数”的用户ID挑出来加到一个临时表,还有其它的相关业务的用户ID也挑出来加到临时表……
最好依据临时表内的用户ID分批对用户重新计算。