转自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:
<PacketHeader>
<Type>
<BYTE>07 </BYTE>
</Type>
<Status>
<BYTE>01 </BYTE>
</Status>
<Length>
<BYTE>00 </BYTE>
<BYTE>26 </BYTE>
</Length>
<SPID>
<BYTE>00 </BYTE>
<BYTE>00 </BYTE>
</SPID>
<Packet>
<BYTE>01 </BYTE>
</Packet>
<Window>
<BYTE>00 </BYTE>
</Window>
</PacketHeader>
<PacketData>
<BulkLoadBCP>
<COLMETADATA>
<TokenType>
<BYTE>81 </BYTE>
</TokenType>
<Count>
<USHORT>01 00 </USHORT>
</Count>
<ColumnData>
<UserType>
<ULONG>00 00 00 00</ULONG>
</UserType>
<Flags>
<USHORT>05 00 </USHORT>
</Flags>
<TYPE_INFO>
<FIXEDLENTYPE>
<BYTE>32 </BYTE> </FIXEDLENTYPE>
</TYPE_INFO>
<ColName>
<B_UNICODE>
<BYTELEN>
<BYTE>02 </BYTE>
</BYTELEN>
<BYTESascii="c.1.">63 00 31 00 </BYTES>
</B_UNICODE>
</ColName>
</ColumnData>
</COLMETADATA>
<ROW>
<TokenType>
<BYTE>D1 </BYTE>
</TokenType>
<TYPE_VARBYTE>
<BYTES>00 </BYTES>
</TYPE_VARBYTE>
</ROW>
<DONE>
<TokenType>
<BYTE>FD </BYTE>
</TokenType>
<Status>
<USHORT>00 00 </USHORT>
</Status>
<CurCmd>
<USHORT>00 00 </USHORT>
</CurCmd>
<DoneRowCount>
<LONGLONG>00 00 00 00 00 00 00 00</LONGLONG>
</DoneRowCount>
</DONE>
</BulkLoadBCP>
</PacketData>
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();
}
前一种方法是直接给定数据文件名等参数,适用于给定文件直接导入。后一种方法逐行处理,每次输入一个字符串数组,其中每个数组元素代表一个列的值。
分享到:
相关推荐
求一条生成十六进制的BCP语句
BCP(Bulk Copy Program)是SQL Server数据库管理系统中用于大量数据导入导出的实用程序,它允许用户快速高效地处理大量的数据迁移任务。在本文中,我们将深入探讨使用Delphi开发BCP小工具的相关知识点。 首先,...
5. **演练与改进**:定期进行BCP演练,检查计划的有效性和可行性,根据演练结果调整和完善计划。 6. **持续监控与维护**:随着业务环境的变化,BCP需要不断更新和维护,确保其始终适应企业的实际需求。 **BCP的...
"浪潮BCP双机安装" 浪潮BCP双机安装是指使用浪潮BCP(Business Continuity Planning)软件在双机环境中实现灾难恢复和业务连续性解决方案。BCP软件是浪潮公司开发的一款基于IT服务管理的灾难恢复解决方案,旨在帮助...
**BCP工具Windows详解** BCP(Bulk Copy Program)是微软SQL Server提供的一款强大的数据导入导出工具。它允许用户在SQL Server与外部文件之间进行大量数据的快速传输,而无需通过SQL查询或图形界面。在Windows环境...
### bcp导入导出数据:理解SQL Server与Sybase数据库数据迁移 在IT行业中,数据库管理与维护是一项至关重要的任务,特别是在数据迁移、备份或恢复过程中。`bcp`(Bulk Copy Program)作为SQL Server和Sybase数据库...
通过这种方式,开发人员可以根据具体需求实现或改进PPP连接的带宽控制,提高网络效率。在实际部署时,需要注意的是,BCP的设置和优化可能需要根据网络环境和负载进行调整,以达到最佳性能。同时,由于这个patch适用...
BCP(Bulk Copy Program)是SQL Server提供的一种批量数据导入导出工具,它允许用户高效地将大量数据从操作系统文件传输到SQL Server数据库,或者从数据库导出到文件。在IT行业中,BCP文件通常存储着数据库表的数据...
bcp命令的使用和常见问题处理 bcp命令是Sybase数据库中的一种bulk copy工具,用于将数据从文本文件导入到Sybase数据库中。下面将对bcp命令的使用和常见问题进行详细的讲解。 bcp命令的基本使用 bcp命令的基本语法...
**标题与描述解析** 标题"sybase bcp命令详解"提到了`bcp`命令,这...提供的文档如`bcp命令参数详解.doc`、`bcp.txt`和`BCP.wps`会更深入地介绍每个参数的细节和实际操作示例,是学习和使用`bcp`命令的重要参考资料。
### Mikrotik RouterOS BCP 教程:使用 PPP 封装网桥 #### 概述 本教程旨在介绍如何在Mikrotik RouterOS上配置BCP(Bridge Control Protocol,桥接控制协议),以便通过PPP(Point-to-Point Protocol,点对点协议...
PowerBuilder是一款流行的、基于事件驱动的.NET和Java应用程序开发环境,尤其擅长数据窗口组件,用于与数据库交互。通过PowerBuilder,开发者可以构建用户界面,并利用内置的SQL命令或存储过程与数据库进行交互。...
Sybase BCP(Bulk Copy Program)是Sybase数据库系统中一个强大的数据导入和导出工具。它允许用户高效地批量处理大量数据,无论是从文本文件导入到数据库,还是从数据库导出到文件。BCP在数据库管理和数据分析场景中...
【标题】:“VB的BCP程序,测试成功” 在信息技术领域,VB(Visual Basic)是一种由微软公司开发的可视化编程工具,它基于Basic语言,以其简单易用和强大的功能受到许多程序员的喜爱。BCP(Bulk Copy Program)是...
标题与描述概述的知识点主要涉及如何使用SQL Server的BCP命令行工具将数据导出到Excel文件中。BCP(Bulk Copy Program)是SQL Server提供的一种高效的数据导入导出工具,能够快速地将大量数据从数据库复制到文本文件...
bcp 命令详解+实例 bcp 命令是 SQL Server 中的一个命令行工具,负责导入导出数据。它基于 DB-Library,能够以并行的方式高效地导入导出大批量的数据。bcp 命令可以在控制台执行,也可以通过调用 SQL Server 的一个...
Sybase 数据库 BCP 问题总结 Sybase 数据库 BCP 问题总结是指在使用 Sybase 数据库的 BCP 工具时可能遇到的错误和注意事项。BCP 是 Sybase 数据库中的一个重要工具,用于导入和导出数据,但是如果不正确地使用 BCP...
bcp复制工具是SQL Server提供的一种强大的命令行工具,用于快速、高效地导入和导出数据,无需启动图形用户界面。它基于DB-Library,支持并行处理,适合大量数据的批量操作。 **主要参数及功能** 1. **动作参数**:...
### BCP 工具详解及参数说明 #### 概述 `bcp` 是一个功能强大的工具,主要用于在 Microsoft SQL Server 2000 实例和数据文件之间以用户指定的格式复制数据。通过 `bcp` 工具,用户可以高效地导入导出大量数据。本文...