大数据量更新某个字段的值如何提高效率.

近期由于安全等保测评要求必须提高数据库信息的安全等级, 需要对已有数据进行加密处理… 表W_Report 有1千万左右的数据, 如果用ado.net 批量查出来一批,for循环内存中逐条加密后再update回去的方式. 初步测试了一下每秒 21 条.

这种肯定 是最原始的方案,1千万条估算了下要80小时, 全部处理完要3天. 升级过程中得停止系统. 业务停3天是不可能的. 再加上其它的服务器硬件给力, 算每秒100条, 最起码也要停16个小时. 这肯定不行.

毛主席教导我们: 只要脑袋不熄火,办法总比困难多.

下面采用了新的方案批量处理,

新方案的思路是
第一步:将数据按月份分批批量加载到系统内存中,一次性加载1个月的. 大概有20万条数据. 使用Ado.net 读取到 DataReader,
第二步:逐行处理,在内存中计算加密后的数据,然后保存到DataTable
第三步:使用SqlBulkCopy 批量将加密后的DataTable 插入到一张临时表
第四步:使用Update语句一次性将临时表的数据更新到老表
第五步:清空临时表中的数据, 准备处理下一个月的数据.

此方案每一步的隐患都很多
第一步:不知道加载时间多少.
第二步:少不了的计算时间
第三步:SqlBulkCopy 批量插入10万条数据据说只要1-2秒.
第四步:Update语句用一个表去更新另外一个表的性能不知如何.
第五步:清空临时表,可以使用直接删表的方式, 速度会很快.秒秒钟.

为了不做无用功, 先测验第四步的性能如何:
1.先取一个月的数据插入到临时表当作测试用. 共取了 157375条数据 用时不到1秒
这里只取了3个需要加密的字段和主键.

select  Id, PatientName,PatientIDCard,PatientPhone  into TempReportNewData from W_Report WHERE ReportTime  BETWEEN '2019-11-01' and '2019-11-30' 

第一次测试. 无主键 再更新回去到老表 用时 157375条数据 272.486s 平均每秒578条数据

update W_Report 
set 
PatientName = tmp.PatientName,
PatientIDCard = tmp.PatientIDCard,
PatientPhone = tmp.PatientPhone
from TempReportNewData as tmp
where W_Report.Id = tmp.Id

第二次测试. 加主键后 再更新回去 用时 157375条数据 279.281s 平均每秒576条数据
比原来的还慢了点, 影响不大.先不管了, 当作没变化.

第三次测试,. 在主表的更新条件中加时间索引字段作为条件.157375条数据 用时 4.055s秒
我当时就傻眼了. 这么快的速度.

update W_Report 
set 
PatientName = tmp.PatientName,
PatientIDCard = tmp.PatientIDCard,
PatientPhone = tmp.PatientPhone
from TempReportNewData as tmp
where W_Report.Id = tmp.Id 
and W_Report.ReportTime  BETWEEN '2019-11-01' and '2019-11-30'

至此,第四步的效率从一定的程度上来看,还是可以接受的,
时间范围半个月应该更快, 因为有时间索引做过滤条件可以大幅提高更新速度. 毕竟时间索引可以跳过好多数据的排查过程. 灵活运用索引很有必要.
在这次的测试过后,又冒出来一个新的想法, 可以先把前面的3步提前做了.先逐条计算好放到临时表中. 然后等升级切换的时候再批量分批一个月一个月的更新到W_report
那就是分分钟的事情了. 毕竟这些3个月之前的老数据这些字段的数据是不会变的. 可以提前做.

明天再继续测试 取数据的效率和加密的效率.

反正步骤1,2,3可以提前做, 慢点也无所谓, 压力不大了.

又过了一天.经过同事测试,发现我昨天的写的代码效率变低了. 1000多条就要50多秒, 这是为何?
后来同事排查了一下发现

UPDATE W_Report
SET PatientName = tmp.PatientName,
 PatientIDCard = tmp.PatientIDCard,
 PatientPhone = tmp.PatientPhone
FROM
 TempReportNewData AS tmp
WHERE
 W_Report.Id = tmp.Id
AND W_Report.ReportTime BETWEEN '2019-09-27 00:00:00' AND '2019-09-28 00:00:00'
AND tmp.ReportTime BETWEEN '2019-09-27 00:00:00' AND '2019-09-28 00:00:00'

他的语句中加了时分秒, 然后就慢了好几个数量级.

经过测试前面3步 按天从数据库读出来,再计算,然后再批量使用SqlBulkCopy 插入,经过测试34万条数据用了30秒. 速度也是非常快的.

处理大规模数据时,可以采取以下几种方法来提高效率: 1. 批量处理:将大规模数据分批处理,避免一次性处理所有数据。可以将数据按照一定的规模划分为多个批次,逐批进行处理。这样可以降低单次处理的数据量,减少内存占用和处理时间。 2. 并行处理:利用多线程或分布式计算等方式进行并行处理,同时处理多个数据块。通过并行处理,可以充分利用多核CPU或多台机器的计算资源,加快处理速度。 3. 数据索引优化:对于需要频繁查询和筛选的字段,可以创建索引以提高查询效率。索引可以加快数据的查找速度,减少系统的IO操作。 4. 数据预处理:在导入数据之前,进行必要的预处理操作,如去除无效数据、修复错误数据、标准化数据格式等。通过预处理可以减少后续处理的数据量和复杂度,提高整体处理效率。 5. 垂直拆分和水平拆分:如果可能,可以将大规模数据按照业务或其他逻辑进行垂直拆分或水平拆分。垂直拆分是将不同业务或功能的数据存储在不同的表或数据库中,水平拆分是将数据按照某个维度进行划分存储在不同的表或数据库中。这样可以减少单个数据表的数据量,提高查询和处理效率。 6. 使用高性能数据库:选择适合大规模数据处理的高性能数据库,如分布式数据库或列式数据库等。这些数据库通常具有更好的扩展性和并发性能,能够更好地应对大规模数据的处理需求。 7. 缓存优化:对于经常被查询的数据,可以使用缓存技术将其缓存到内存中,减少数据库查询的次数,提高查询效率。 需要根据具体情况综合考虑以上方法,并结合系统架构、硬件资源等进行合理的优化。同时,注意在处理大规模数据时要进行性能测试和监控,及时发现和解决潜在的性能问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值