抓取到的数据, 要批量写数据到 ORACLE , 一开始是用的EF, 处理速度很慢.
主要表现在验证数据上(db.GetValidationErrors), 每分钟才能写 1000条不到.
换成 EnterpriceLibrary.Validation (Validation.Validate) 后, 验证速度大增, 1000条只需几秒钟.
但是整体速度还是慢, 是因为每条数据都被EF转换为一个INSERT语句.
 
我花了一些时间用 OracleBulkCopy (需要引用客户端下面的 Oracle.DataAccess.dll ) 重写了这部份的逻辑, 1000条写到写ORACLE中也不过几秒时间, 直接从牛车跨越到高铁时代.
 
         private void BulkCopy(string connStr, DataTable dt, string tblName) {
             ) {
                 using (var bc = new OracleBulkCopy(connStr)) {
                     bc.DestinationTableName = tblName;
                     foreach (DataColumn col in dt.Columns) {
                         bc.ColumnMappings.Add(col.ColumnName, col.ColumnName);
                     }
                     bc.WriteToServer(dt);
                 }
             }
         }

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

        /// <summary>
         /// 将 List 转换为 DataTable, 只针对 T 中 的 public Property
         /// </summary>
         /// <typeparam name="T"></typeparam>
         /// <param name="list"></param>
         public static DataTable ToDataTable<T>(this List<T> list) where T : class {
             if (list == null)
                 return null; 

             Type type = typeof(T);
             var ps = type.GetProperties().Where(p => p.CanWrite && (p.PropertyType.IsValueType || p.PropertyType.IsPrimitive || p.PropertyType == typeof(String)));
             Type targetType;
             NullableConverter nullableConvert;
             List<DataColumn> cols = new List<DataColumn>();
             foreach (var p in ps) {
                 if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
                     nullableConvert = new NullableConverter(p.PropertyType);
                     targetType = nullableConvert.UnderlyingType;
                     cols.Add(new DataColumn(p.Name, targetType));
                 } else {
                     cols.Add(new DataColumn(p.Name, p.PropertyType));
                 }
             } 

             DataTable dt = new DataTable();
             dt.Columns.AddRange(cols.ToArray()); 

             list.ForEach((l) => {
                 List<object> objs = new List<object>();
                 objs.AddRange(ps.Select(p => p.GetValue(l, null)));
                 dt.Rows.Add(objs.ToArray());
             }); 

             return dt;
         } 
这段代码是我几年前用存储过程的时代写的, 现在还能用上.
只将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也不高了!
 

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

  1. redis-server进程CPU百分百问题

    结论:待确认是否为redis的BUG,原因是进程实际占用的内存远小于配置的最大内存,所以不会是内存不够需要淘汰.CPU百分百redis-server进程集群状态:slave临时解决办法:使用gdb将d ...

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

    线程池应该设置多少线程合适,怎么样估算出来.最近接触到一些相关资料,现作如下总结. 最开始接触线程池的时候,没有想到就仅仅是设置一个线程池的大小居然还有这么多的学问,汗颜啊. 首先,需要考虑到线程池所 ...

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

    基本概念 cpu亲和性(affinity) CPU的亲和性, 就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,也称为CPU关联性:再简单的点的描述就将指定的进程或线程绑定到相应的 ...

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

    Part0 遇到了故障怎么办? 在生产上,我们会遇到各种各样的故障,遇到了故障怎么办? 不要慌,只有冷静才是解决故障的利器. 下面以一个例子为例,在生产中碰到了CPU 100%的问题怎么办? 在生产中 ...

  5. 进程、线程、协程、CPU

    进程.线程.CPU 进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.或者说进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进 ...

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

    关闭所有 .................................. .连接: ##把全部的MySQL连接kill掉for i in $(mysql -uroot -p123456 -Bse ...

  7. REdis CPU百分百问题分析

    REdis版本:4.0.9 运行环境:Linux 3.10.107 x86_64 gcc_version:4.8.5 结论:是一个BUG,在4.0.11版本中被作者antirez所修复 现象: 1)  ...

  8. 使用脚本快速线程转储及列出高cpu线程

    jstack `ps -ef | grep java | grep bocai.jar | awk '{print $2}'` > cpu_high.logtop -b -n1 -Hp `ps ...

  9. linux进程、线程与cpu的亲和性(affinity)

    参考:http://www.cnblogs.com/wenqiang/p/6049978.html 最近的工作中对性能的要求比较高,下面简单做一下总结: 一.什么是cpu亲和性(affinity) C ...

随机推荐

  1. 基础知识复习(二)——stdafx.h 头文件及x&(x-1)运算

    今天好久没写过C++程序了,使用VS2013 新建空的控制台程序,结果自动生成了头文件和main 方法. 就了解了stdafx.h头文件的含义及用法. stdafx:standard Applicat ...

  2. NGUI Atlas, Atlas Type Reference

    在NGUI中,通过创建图集及引用图集,实际使用时指定引用图集而非具体图集本身,可以创建多语言,或高配低配版本资源包. NGUI Atlashttp://www.cnblogs.com/answerwi ...

  3. VS2010 添加服务引用以后点不出引用服务的命名空间

    声明:本次我遇到的仅是这类情况中的其中一个个例,不要拘泥于些噢! 问题描述: 1.我建了一个新项目,不引用服务前是好的,可以打点点出任何已有有命名空间,但是引用服务以后就是点不出服务的命名空间. 2. ...

  4. apache开启.htaccess

    1 . 如何让的本地APACHE开启.htaccess 如何让的本地APACHE开启.htaccess呢?其实只要简朴修改一下apache的httpd.conf设置就让APACHE.htaccess了 ...

  5. 介绍开源的.net通信框架NetworkComms框架之七 数据加密通信

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

  6. 使用OpenFileDialog会更改默认程序目录

    这个问题可能只有在特定的程序中会发现:当我们在程序中使用相对路径时是依赖于当前目录的.所以在使用类似代码: XElement rootNode = XElement.Load(@"zips/ ...

  7. 1172. Ship Routes

    http://acm.timus.ru/problem.aspx?space=1&num=1172 水题DP   大整数直接上java 代码: import java.math.BigInte ...

  8. PHP 函数

    字符串函数: $name = "fakeface"; $myname =substr($name,0,3);//输出前面三个字符 fak print $myname; $name ...

  9. SSH框架构建微信公众帐号服务器小技巧

    SSH框架构建微信公众帐号服务器小技巧 熟悉struts2和servlet的同学应该清楚,struts2的方法多样性弥补了servlet单一的doGet 和doPost方法.如果自己的公众账号服务器是 ...

  10. net 的单元测试 初学

    1. 都要以一个方法 这样的去测试 2. 利用工具 Install-Package Moq -Version 4.0 (最高的是4.5  4.0适用于自己项目的版本)   Moq.dll 进行测试   ...