在线程中用 OracleBulkCopy 导至 CPU 百分百

抓取到的数据, 要批量写数据到 ORACLE , 一开始是用的EF, 处理速度很慢.

主要表现在验证数据上(db.GetValidationErrors), 每分钟才能写 1000条不到.

换成 EnterpriceLibrary.Validation (Validation.Validate) 后, 验证速度大增, 1000条只需几秒钟.

但是整体速度还是慢, 是因为每条数据都被EF转换为一个INSERT语句.

我花了一些时间用 OracleBulkCopy (需要引用客户端下面的 Oracle.DataAccess.dll ) 重写了这部份的逻辑, 1000条写到写ORACLE中也不过几秒时间, 直接从牛车跨越到高铁时代.

 1         private void BulkCopy(string connStr, DataTable dt, string tblName) {
 2             if (dt.Rows.Count > 0) {
 3                 using (var bc = new OracleBulkCopy(connStr)) {
 4                     bc.DestinationTableName = tblName;
 5                     foreach (DataColumn col in dt.Columns) {
 6                         bc.ColumnMappings.Add(col.ColumnName, col.ColumnName);
 7                     }
 8                     bc.WriteToServer(dt);
 9                 }
10             }
11         }

connStr 是 ORACLE 的连接字符串, tblName 是目标表的表名.

 1        /// <summary>
 2         /// 将 List 转换为 DataTable, 只针对 T 中 的 public Property
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         /// <param name="list"></param>
 6         public static DataTable ToDataTable<T>(this List<T> list) where T : class {
 7             if (list == null)
 8                 return null;
 9
10
11             Type type = typeof(T);
12             var ps = type.GetProperties().Where(p => p.CanWrite && (p.PropertyType.IsValueType || p.PropertyType.IsPrimitive || p.PropertyType == typeof(String)));
13             Type targetType;
14             NullableConverter nullableConvert;
15             List<DataColumn> cols = new List<DataColumn>();
16             foreach (var p in ps) {
17                 if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
18                     nullableConvert = new NullableConverter(p.PropertyType);
19                     targetType = nullableConvert.UnderlyingType;
20                     cols.Add(new DataColumn(p.Name, targetType));
21                 } else {
22                     cols.Add(new DataColumn(p.Name, p.PropertyType));
23                 }
24             }
25
26
27             DataTable dt = new DataTable();
28             dt.Columns.AddRange(cols.ToArray());
29
30
31             list.ForEach((l) => {
32                 List<object> objs = new List<object>();
33                 objs.AddRange(ps.Select(p => p.GetValue(l, null)));
34                 dt.Rows.Add(objs.ToArray());
35             });
36
37
38             return dt;
39         } 

这段代码是我几年前用存储过程的时代写的, 现在还能用上.

只将T中的可写的 值类型, 基元类型 和字符串映射到 DataTable 中.

因为 EF 生成的实体类中, 导航属性并不是于数据库中的字段.

CLR 中的基元类型有:

Boolean 、 Byte 、 SByte 、 Int16 、 UInt16 、 Int32 、 UInt32 、 Int64 、 UInt64 、 IntPtr 、 UIntPtr 、 Char 、 Double  和  Single 。

https://msdn.microsoft.com/zh-cn/library/system.type.isprimitive.aspx

String 不是基元类型, 而且是地址引用的, 但它是一个特殊.

除 字符串,基元类型,值类型的属性, 我还真找不出来哪个可以映射到数据库中.

本地调试没问题后,放到服务器上, CPU居然高居不下.

生成DUMP文件, 用 WinDbg 查看:

0:000> .load sos.dll
0:000> !threadpool
CPU utilization: 96%
Worker Thread: Total: 0 Running: 0 Idle: 0 MaxLimit: 32767 MinLimit: 3
Work Request in Queue: 0
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 6 CurrentLimit: 1 MaxLimit: 1000 MinLimit: 3 

CPU 使用率 96%

杳看线程执行时间:

0:000> !runaway
 User Mode Time
  Thread       Time
  21:13dc      0 days 0:39:58.140
  24:13d4      0 days 0:08:41.750
  27:11ac      0 days 0:01:29.906
   5:1250      0 days 0:00:18.796 

查看21号线程的堆栈:

~21s
!clrstack
OS Thread Id: 0x13dc (21)
Child SP               IP Call Site
000000002595e7f8 00000000777e85d7 [HelperMethodFrame: 000000002595e7f8]
000000002595e910 000007fe9482b688 *** ERROR: Module load completed but symbols could not be loaded for Oracle.DataAccess.dll
Oracle.DataAccess.Client.OracleTuningAgent.DoScan()
000000002595e950 000007fe9481d28f Oracle.DataAccess.Client.OracleTuningAgent.TuningFunction()
000000002595e9c0 000007fef0bdd0b5 *** WARNING: Unable to verify checksum for mscorlib.ni.dll
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000002595eb20 000007fef0bdce19 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000002595eb50 000007fef0bdcdd7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000002595eba0 000007fef0b50301 System.Threading.ThreadHelper.ThreadStart()
000000002595eeb8 000007fef1c7ffe3 [GCFrame: 000000002595eeb8]
000000002595f1e8 000007fef1c7ffe3 [DebuggerU2MCatchHandlerFrame: 000000002595f1e8]
000000002595f3c8 000007fef1c7ffe3 [ContextTransitionFrame: 000000002595f3c8]
000000002595f5b8 000007fef1c7ffe3 [DebuggerU2MCatchHandlerFrame: 000000002595f5b8]  

接连查了几个线程的堆栈, 都是这个: 
Oracle.DataAccess.Client.OracleTuningAgent.XXX

搜了一下 Oracle.DataAccess.Client.OracleTuningAgent.TuningFunction : 
http://stackoverflow.com/questions/2782169/oracle-data-provider-pegs-iis-worker-process-when-web-site-is-stopped

This has been fixed in 11.2.0.2 and in Patch 9966926 ORACLE 11G 11.2.0.1 PATCH 5 BUG FOR WINDOWS (64-BIT AMD64 AND INTEL EM64T). 
Or WORKAROUND: is to disable self tuning by adding "Self Tuning=false" to the connection string.

看不大懂, 但是里面提及了 Oracle.DataAccess.Client 的版本. 
这个DLL 我是从客户端: 11.2.0 中考出来的, 版本是: 2.112.1.0

Self Tuning 从 VS 的数据库连接管理中, 可以看出它的意思是:

对连接启用或禁用自我优化

具体有什么功效, 什么影响没有去查证. 先不管.

从ORACLE上下载了一个 ODAC121021_x64 (客户端) , 200多M, 安装后, ODP.NET 目录下面有两个文件夹 2.X 和 4

引用 4 下面的 Oracle.DataAccess.dll (版本: 4.121.2.0),  本地运行也是毫无压力,很完美.

拿这个DLL直接替换到服务器上, 结果 CPU 是不高了, 但是连写都不写了!

不知道是不是需要安装最新的客户端, 没有试验. 也不能去实验, 因为基础环境一改,会影响一大片.

索性还拿 2.x 的版本, 在连接字符串中加入 Self Tunning = False, 放到服务器上, 数据正常写入了, CPU也不高了!

时间: 2024-11-02 15:59:42

在线程中用 OracleBulkCopy 导至 CPU 百分百的相关文章

在子线程中更改主线程中的控件的信息,在子线程中用toast

一丶在子线程中不允许更改主线程中的控件的信息,也不允许在子线程中用toast,我们要更改的话 (1)消息机制:使用handler (由主线程调用) 在主程序中Handler handler = new Handler(){ public void handleMessage(Message msg){ int type = msg.what ;//拿到msg的类型,再判断            switch (type) {                case SUCCESS:      

[转] 写个软件来防止服务器网站 CPU 百分百

问题: 大概每隔两个星期左右,秋色园上服务器就会来一次 CPU 百分百,由于问题发生的概率极低,要它重现也难,所以只能意淫是内存太少的原故.以前出现,远程上去结束掉进程,就正常了, 悲剧的是最近秋色园 VPS 不知啥原因,经常远程不上去, 最后转转折折只能进 VPS 管理后台重启.要遇上 CPU 百分百,又是需要机缘,所以一旦发生和遇到解决的时间差度大,就会造成服务器长时间打不开,后果大伙都懂的... 解决: 方法一:设置应用池CPU策略,达到N的时候自动回收进程(不实用,排除) 因为更新网站

linux 将进程或者线程绑定到指定的cpu上

基本概念 cpu亲和性(affinity) CPU的亲和性, 就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,也称为CPU关联性:再简单的点的描述就将指定的进程或线程绑定到相应的cpu上:在多核运行的机器上,每个CPU本身自己会有缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他CPU上,如此,CPU cache命中率就低了,当绑定CPU后,程序就会一直在指定的cpu跑,不会由操作系统调度到其他CPU上,性能有一定的提高. 软亲和性(affinity) 就是进程要在指

线程池大小设置,CPU的核心数、线程数的关系和区别,同步与堵塞完全是两码事

线程池应该设置多少线程合适,怎么样估算出来.最近接触到一些相关资料,现作如下总结. 最开始接触线程池的时候,没有想到就仅仅是设置一个线程池的大小居然还有这么多的学问,汗颜啊. 首先,需要考虑到线程池所进行的工作的性质: IO密集型 CPU密集型 简单的分析来看,如果是CPU密集型的任务,我们应该设置数目较小的线程数,比如CPU数目加1.如果是IO密集型的任务,则应该设置可能多的线程数,由于IO操作不占用CPU,所以,不能让CPU闲下来.当然,如果线程数目太多,那么线程切换所带来的开销又会对系统的

面试官:CPU百分百!给你一分钟,怎么排查?有几种方法?

Part0 遇到了故障怎么办? 在生产上,我们会遇到各种各样的故障,遇到了故障怎么办? 不要慌,只有冷静才是解决故障的利器. 下面以一个例子为例,在生产中碰到了CPU 100%的问题怎么办? 在生产中真的碰到了CPU 100%的问题,再来看这篇文章已经迟了,还是先来模拟演练下吧. 怎么模拟演练? (1)查找资料,选型排查CPU高负载问题的工具. (2)安装一个高负载程序或手写个高负载应用部署. (3)安装.执行分析工具,实战分析,找出故障原因. (4)思考与总结. Part1 工具选型 因为现在

mysql连接卡死,很多线程sleep状态,导致CPU中mysqld占用率极高

关闭所有 .................................. .连接: ##把全部的MySQL连接kill掉for i in $(mysql -uroot -p123456 -Bse "show processlist" | awk '{print $1}');do mysql -uroot -p123456 -e "kill $i";done ##把admin用户的连接kill掉for i in $(mysql -uroot -p123456 -

如何查看服务器CPU核心数和线程数

知道服务器CPU型号,那么我们如何在服务器里面查看服务器CPU核心数和线程数呢? 步骤: 先用鼠标右键点击屏幕最下方的任务栏空白处.会弹出一个菜单. 在菜单中用鼠标左键点选“启动任务管理器”. 点击任务管理器的“性能”选项. 在“性能”选项的“cpu使用记录”项中有几个方框就说明cpu有几个线程. cpu线程数不一定等于cpu的核心数,因为有些cpu采用了超线程技术,一个核心可以有两个线程.如果想查看cpu的核心数可以安装一个CPU-Z软件,打开后就可以看见有几个核心和线程了. PS:超线程处理

java进程占用cpu过高分析是哪些线程

拿hbase基准测试列子来分析哪些线程使用比较高的cpu,环境是linux,基准测试命令: hbase org.apache.hadoop.hbase.PerformanceEvaluation  --rows=500000 --nomapred --presplit=5 --writeToWAL=true randomWrite 5 首先查看占用cpu最高的进程和线程id,执行命令: [[email protected] logs]$ ps Hh -eo pid,tid,pcpu | sort

Qt线程(4) 降低线程占用CPU

问题描述: 一般将计算量大的处理过程单独放置到一个单独的线程处理,因此很有可能你的处理过程需要while(1)或类似的操作. 也因此很有可能造成线程在处理时计算机CPU占用过高的情况. 解决办法: 降低相应线程优先级 sleep 具体实现: 1.创建工作线程 1 #include <QThread> 2 #include <QDebug> 3 #include <QMutex> 4 #include <QMutexLocker> 5 6 #include &