当前位置:我的异常网» 编程 » [转] Java BCP 改善

[转] Java BCP 改善

www.myexceptions.net  网友分享于:2015-08-26  浏览:108次

[转] Java BCP 改进

转自http://blog.csdn.net/kaopusoft/article/details/7371206

BCP(Bulk CopyProgram批量数据拷贝工具,下同)是MicrosoftSQL Server和Sybase数据库提供的非常实用的数据导入/导出工具。它方便实用,性能卓越。深得程序员的喜爱。

在项目开发过程中,需要在Java应用里用定时任务实现数据的批量导入/导出。常规的做法是用insert into语句直接插入数据,或者调用BCP命令导入数据。但这两种方法都有其固有的局限性,有没有一种更为方便的方法呢?

思路

数据导出功能较易实现。只要用Statement直接执行SQL语句返回ResultSet,然后将查询结果序列化为字符串后写到文本中去。唯一需要注意的是创建Statement时一定要指定游标类型为只读(CONCUR_READ_ONLY)和前向读取(TYPE_FORWARD_ONLY),否则可能造成内存溢出。

难点是在数据导入。

使用insert into语句的方式插入数据,数据库服务器的负荷将迅速增大,日志会迅速增大甚至溢出。在实时业务系统中运用时,必须要在插入若干条后暂停并清理日志,不仅处理效率低,而且可能造成业务中断。

直接调用BCP命令的前提是要安装和配置Sybase或Microsoft SQL Server(后文中均简写为SQL Server)客户端,并且需要根据数据库类型不同,定位到不同的BCP.exe文件路径,在应用程序中也很难得到数据导入的情况。

有一个叫jBCP的开源项目,作者声称可以将数据从文件导入到 SQL Server和Sybase数据库。经过初步测试,jBCP的导入仅仅能适用于Sybase,且要导入的表至少需要满足下列条件:

1.所有字段不能为空;

2.字段值不能包含中文字符;

3.表不能包含tinyint类型的字段;

也就是说,对于BCP功能,jBCP提供的包并不具备商用条件。

尽管如此,jBCP为我们提供了解决问题的基本思路和方法,那就是直接用TDS协议与数据库进行TCP通信,向服务端发送BCP命令和数据。

数据库客户端和服务端的通信并不像我们想象的那样神秘。我们知道,数据库服务也是作为Socket服务端响应客户端连接请求的。例如在缺省状态下,SQL Server通常的端口号是1433,Oracle的端口号是1521,Sybase的端口号是5000。要跟数据库通信,就得先建立Socket连接,然后使用数据库特有的协议进行消息交互。

对于SQL Server和Sybase,它使用的Socket通信协议是TDS(Tabular Data Stream Protocol,表格化数据流协议,下同)。TDS版本和数据库的版本对应关系如下表:

TDS 版本

支持产品及版本

4.2

Sybase SQL Server < 10 和 Microsoft SQL Server 6.5

5.0

Sybase SQL Server >= 10

7.0

Microsoft SQL Server 7.0

8.0

Microsoft SQL Server 2000

9.0

Microsoft SQL Server 2005

由于Sybase10以下版本和Microsoft SQL Server6.5版本目前较少使用,本文中所指的数据库均以TDS5.0以上版本为准,同时也不针对Sybase10以下版本和Microsoft SQL Server6.5做兼容性测试。

BCP 导出功能jBCP包并没有实现。但bcp导出的过程实际上是执行Select * from table,然后把字段数据根据规则写入文件。我们可以用这个方法自行实现。

在TDS协议中,规定了导入的Bulk Copy Packet的格式。一个典型的BCP导入会话过程如下:

--> 建立连接并认证

--> 声明将要进行BCP操作(insert bulk数据库名..表或视图名)

--> 结构化数据

--> 数据结束(TDS7.0+, 即SQL Server才需要)

由此可见,BCP导入的过程实际上是数据库服务端先准备好接收BCP数据,然后由客户端发送二进制的字段数据给服务端,服务端将这些数据快速写入数据库。归纳起来,BCP性能高的原因如下:

1.单向发送数据,避免频繁的请求/响应操作,也减少了网络交互包的数量;

2.服务端不处理SQL语句,避免做语法分析、预编译等操作;

3.服务端不做数据类型映射转换;

4.客户端直接向Socket连接写数据流,避免其它多余环节;

5.对于快速BCP,服务端不产生日志,仅记录页分配。

实践

结合搜集到的BCP资料,综合运用抓包工具、比较工具分析后,笔者修改了jBCP的源代码。经过测试,解决了jBCP不能正常工作的问题。

笔者使用Ethereal来抓取BCP客户端发送到服务端的数据包,将它与用jBCP发送的数据包用UltraEdit的二进制比较工具进行比较,然后将它与TDS协议文档进行逐字段对应,试图发现导入失败的原因和规律。

经过反复分析和验证,笔者总结出了TDS协议的BCP请求包结构。

1.     SybaseBCP请求包结构

TDS5.0协议(适用于Sybase10以上)中的BCP请求数据包,可以简单解析如下:

BCP包结构:

TDS包头   8字节

行记录1

行记录2

……

行记录N

行记录结构:

本行长度    双字节整数,单位为字节

变长列数量  单字节整数

0x00

定长字段1   长度根据字段定义确定

定长字段2   长度根据字段定义确定

……

定长字段N   长度根据字段定义确定

本行长度     双字节整数(与前一个记录长度相同)

变长字段1   长度根据字段实际长度计算

变长字段2   长度根据字段实际长度计算

……

变长字段N   长度根据字段实际长度计算

校正表(可选)  偏移表都是单字节,不够用的时候启用校正表

偏移表       记录变长字段的偏移位置

2.     SQLServer BCP 请求包结构

TDS7.0及以上协议(适用于SQL Server7.0以上)中的BCP请求数据包,可以简单解析如下3:

07

01

00

26

00

00

01

00

81

01 00

00 00 00 00

05 00

32

02

63 00 31 00

D1

00

FD

00 00

00 00

00 00 00 00 00 00 00 00

SQL Server的字段是按照字段定义顺序排列的;在BCP发送之前,要发送字段定义包;批量提交时要发送一个表示提交的DONE结构;记录之间使用0xd1作为分隔符。这与Sybase采用的TDS5.0有显著的不同。

3.     jBCP抓包分析及改进

使用未修改的jBCP包导入数据,抓包得到了一个响应结果如下:

0000  00 14 2a 6f d2 eb 00 d0 d0 c6 d5 01 08 00 45 00 ..*o..........E.

0010  00 fa 65 5c 40 003d 06 40 d1 0a 82 30be 0a 82  ..e\@.=.@...0...

0020  51 0f 10 0408 b3 1d 08 6f d8 8d21 af ff 50 18  Q.......o..!..P.

0030  80 00 a0 0e 00 00 04 01 00d2 00 00 00 00 aa be  ................

0040  00 e5 12 00 00 01 10 ac00 42 61 64 20 72 6f77  .........Bad row

0050  20 64 61 74 61 20 72 65 63 65 69 76 65 64 20 66   data received f

0060  72 6f 6d 2074 68 65 20 63 6c 69 656e 74 20 77  rom the client w

0070  68 69 6c 65 2062 75 6c 6b 20 63 6f 70 79 69 6e  hile bulk copyin

0080  67 20 69 6e 74 6f 20 6f 62 6a 65 63 74 20 31 30  g into object 10

0090  34 39 37 36 37 37 36 36 20 69 6e 20 64 61 74 61  49767766 in data

00a0   62 61 73 65 20 37 2e 20 5265 63 65 69 76 65 64  base 7. Received

00b0  20 61 20 72 6f 77 206f 66 20 6c 65 6e 67 74 68   a row oflength

00c0   20 31 37 32 32 33 20 77 6869 6c 73 74 20 6d 61   17223 whilst ma

00d0  78 69 6d 75 6d 20 6f 72 2065 78 70 65 63 74 65  ximum or expecte

00e0  64 20 72 6f 77 206c 65 6e 67 74 68 20 6973 20  d row length is

00f0   39 38 37 2e 0a 06 53 59 42 41 53 45 00 01 00 fd  987...SYBASE....

0100  12 00 03 00 00 00 00 00                          ........

大意是说,对于给定表的字段,列的长度超出了允许范围。这说明发送的BCP请求包与服务端要求的请求包格式不一致。

进一步将jBCP的BCP数据包和bcp工具产生的BCP请求数据包进行比较,陆续发现下列问题:

1.  在BCP消息头部的字段定义处,tinyint字段长度是4字节。但实际tinyint是1个字节。

2.  中文字符的长度,jBCP均以字符数计算,没有用实际字节长度;

3.  Microsoft SQL Server的BCP消息,没有按照协议中规定的批量提交(DONE)标识,且消息头部的字段定义是非必选填入的。

找出这些规律后,再分别修改对应的jBCP源代码,然后进行测试。

4.     jBCP改进后的测试结果

测试硬件环境:

客户端:HP  nc6400 笔记本,Inter 双核T2300 1.66G/1G

服务端:SQLServer: TCL台式机 Inter 双核 2.8G/1G

Sybase: PC Server,Inter 2.4G/2G

测试方法:分别使用SQL Server和Sybase自带的BCP程序做数据导入;用jBCP分别做对应的数据导入。

使用来自于实际生产数据库中的某个日志表作为导入样本。字段数为36个,其中变长字段数为21个,记录数为815,963条,每2000条批量提交一次。

导入类型

平均速度

平均服务端

CPU占用

平均客户端

内存占用

平均客户端

CPU占用

jBCP-> SQL Server

10427.642

18%

23524K

45%

BCP-> SQL Server

18145.01

35%

4964K

24%

jBCP-> Sybase

3509.983

18%

24076K

16%

BCP-> Sybase

3906.47

18%

24724K

12%

从测试结果可以看出,数据库厂商提供的BCP程序性能具有先天的优势,Sybase 的BCP程序较之jBCP优势体现不明显,而SQLServer的BCP程序做了更多优化,其导入速度比jBCP快了1/2到1/3,数据库服务端CPU占用率并不高,性能瓶颈在客户端。而Sybase的BCP优化效率不明显,性能瓶颈在数据库服务器端。

另一方面也再次说明BCP导入方式的优越性,即对数据库服务器的负荷并无大的冲击,几乎可以在实时业务处理数据库中随时进行。

分别使用不同的表结构、带有中文的多个用例做数据导入,全部通过测试。

5.     jBCP的使用方法

jBCP有两种用法:

(1)       一般使用方法

Class.forName("net.sourceforge.jtds.jdbc.Driver");

BCPbcp = DriverManager.getConnection("jdbc:jbcp:sybase://ip:port/dbname", userName, password);

try{

bcp.config(dataFile,errFile, tableName, batchSize, delimiter);

bcp.run();

}

finally {

bcp.close();

}

(2)       高级使用方法

Class.forName("net.sourceforge.jtds.jdbc.Driver");

BCPbcp = DriverManager.getConnection("jdbc:jbcp:sybase://ip:port/dbname", userName, password);

try{

bcp.bcpInit(tableName);

bcp.bcpSendRow(columnsArray); // columnsArray是一个字符串数组

……

bcp.bcpSendRow(columnsArray); // columnsArray是一个字符串数组

……

bcp.bcpBatch();

bcp.bcpSendRow(columnsArray); // columnsArray是一个字符串数组

……

bcp.bcpBatch();

bcp.bcpDone();

}

finally {

bcp.close();

}

前一种方法是直接给定数据文件名等参数,适用于给定文件直接导入。后一种方法逐行处理,每次输入一个字符串数组,其中每个数组元素代表一个列的值。

文章评论

java bcp,[转] Java BCP 改善相关推荐

  1. Java SE和Java EE应用的性能调优

    凡事预则立,不预则废,和许多事情一样,Java性能调优的成功,离不开行动计划.方法或策略以及特定的领域背景知识.为了在Java性能调优工作中有所成就,你得超越"花似雾中看"的状态, ...

  2. Java job interview:Java对象持久化的新的规范JDO

    ●JDO(Java Data Object )是Java对象持久化的新的规范,也是一个用于存取某种数据仓库中的对象的标准化API. ●Java数据对象(Java Data Objects,JDO)是一 ...

  3. java毕业设计——基于java+图像处理技术的医学图像处理系统设计与实现(毕业论文+程序源码)——医学图像处理系统

    基于java+图像处理技术的医学图像处理系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+图像处理技术的医学图像处理系统设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦 ...

  4. java毕业设计——基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现(毕业论文+程序源码)——俄罗斯方块游戏

    基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Java+Java ME的无线网络移动端的俄罗斯方块游戏设计与实现,文章末尾附有 ...

  5. Java面试题 java高级

    八:java高级 1:代码优化 (1)代码优化的目标是: 1 .减小代码的体积 2 .提高代码运行的效率 (2)代码结构层次的优化(目的:更加方便代码的维护–可维护性,可读性) 1.代码注释(代码规范 ...

  6. Java Web和Java后端开发的学习路线

    基础:比如计算机系统.算法.编译原理等等 Web开发: 主要是Web开发相关的内容,包括HTML/CSS/JS(前端页面).Servlet/JSP(J2EE)以及Mysql(数据库)相关的知识.它们的 ...

  7. Java Web和Java后端学习之路

    摘要: 每个阶段要学习的内容甚至是一些书籍.针对Java Web和Java后端开发 java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的 ...

  8. java毕业设计——基于java+eclipse+sqlserver的银行帐目管理系统设计与实现(毕业论文+程序源码)——银行帐目管理系统

    基于java+eclipse+sqlserver的银行帐目管理系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+eclipse+sqlserver的银行帐目管理系统设计与实现, ...

  9. java毕业设计——基于java+Socket+sqlserver的办公自动化系统设计与实现(毕业论文+程序源码)——办公自动化系统

    基于java+Socket+sqlserver的办公自动化系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+Socket+sqlserver的办公自动化系统设计与实现,文章末尾 ...

最新文章

  1. 在Linux的Eclipse下搭建Android环境
  2. java jdbc 链接pg_Java零基础教程
  3. 【Python】matplotlib基础:数据可视化
  4. 学习Kotlin(二)基本语法
  5. python字典append_python中字典重复赋值,append到list中引发的异常
  6. nacos 本地测试_Nacos集群配置实例(windows下测试)
  7. 【POJ - 2632】Crashing Robots(模拟)
  8. dell t40 固态系统盘_笔记本怎么安装固态硬盘 笔记本安装固态硬盘教程【详解】...
  9. jni c 回调 java,JNI - 如何从C ++或C回调到Java?
  10. STM32工作笔记0070---图片显示实验
  11. 如何打造领英朋友圈_领英点赞,请摆好姿势!
  12. rsync 全网备份企业案例
  13. C语言中字符串转数字的方法
  14. 鼠标macOS下定义快捷键(各品牌通用)
  15. 量化投资学习——多因子权重组合优化问题
  16. ubuntu安装pytorch3d
  17. Flixel Dame Tank学习一:半成品坦克大战
  18. java银行账户类_使用Java编写银行账户类(面向对象思考实验)
  19. 在Verilog里边 always@(*)语句是什么意思
  20. PS技巧三------五彩斑斓的黑色(滤镜---镜头光晕和波浪|||||混合选项---柔光)

热门文章

  1. 【建议收藏】Redis超详细入门教程大杂烩
  2. 垃圾分类算法训练及部署
  3. java流星蝴蝶剑下载_PredictionIO 0.9.1 安装步骤
  4. java项目难点_【体验感悟巧化难点为亮点】 java项目技术亮点难点
  5. vue身份证正则校验
  6. Image zImage uImage的关系
  7. Apache伪静态(Rewrite).htaccess文件详解以及RewriteCond 规则
  8. MIPS指令集的常用指令分类和相关解释
  9. JS 转义字符串中特殊字符
  10. 算法复杂度与性能的解释与计算方法