从 oracle 获取 blob 数据时的限制
Posted
技术标签:
【中文标题】从 oracle 获取 blob 数据时的限制【英文标题】:The limitation when getting blob data from oracle 【发布时间】:2013-02-08 06:11:08 【问题描述】:我正在尝试使用 JDBC 从 oracle 下载 BLOB 数据。 为了知道获取 blob 数据的平均响应时间, 我正在使用 JMeter 调用 Getting blob data Java 程序 一个或多个线程。但我得到了奇怪的响应时间,我不能 明白。
我在下面尝试了一些测试。(blob数据大小为1M)
1.在一个线程中使用Jmeter获取blob数据
2.在两个线程中使用Jmeter获取blob数据
3.JMeter在两个线程中获取同一张表中不同的blob数据
4.在两个线程中使用Jmeter在不同的表中获取不同的blob数据。
.从测试1和测试2,我发现测试2的响应时间几乎是测试1的两倍 我无法理解这一点(我的服务器有四个核心,没有人使用它)。 我怀疑当我获得相同的 blob 数据时是否有锁,所以我尝试了测试 3。 但是响应时间和test2差不多。然后我试了test 4 确定我访问同一张表时是否有锁,但响应时间 test 4 也和 test3 一样。
我认为oracle可以同时处理很多用户的请求,所以我不能 了解我从测试中得到的结果。 oracle在同时获取blob数据时是否有一些限制?
这里是获取blob数据的代码
public SampleResult runTest(JavaSamplerContext arg0)
////
try
Class.forName(JDBC_CLASS_NAME);
conn=DriverManager.getConnection(JDBC_THIN+dbserverIp+":"+port+":"+sid,dbuser,userPwd);
statement=conn.createStatement();
rs=statement.executeQuery(sqlText);
responseStr=RESPONSE_DATA_OK_HEAD+KAIGYOU_CODE;
if(rs.next())
String fileId=rs.getString(FILE_ID_COLUMN_NAME);
oracle.sql.BLOB blob=((OracleResultSet)rs).getBLOB(BLOB_COLUMN_NAME);
in=blob.getBinaryStream();
int size=blob.getBufferSize();
byte[] buffer=new byte[size];
int len=-1;
bos=new ByteArrayOutputStream();
while((len=in.read(buffer))!=-1)
readCount=readCount+1;
bos.write(buffer,0,len);
byte[] blobValues=bos.toByteArray();
responseStr=responseStr+fileId+","+blobValues.length+","+readCount+KAIGYOU_CODE;
else
responseStr=RESPONSE_DATA_ZERO;
catch (Exception e)
e.printStackTrace();
getNGSampleResult(e,sr);
return sr;
finally
try
if(rs!=null)
rs.close();
rs=null;
if(statement!=null)
statement.close();
statement=null;
if(conn!=null)
conn.close();
conn=null;
if(in!=null)
in.close();
in=null;
if(bos!=null)
bos.close();
bos=null;
catch (Exception e)
e.printStackTrace();
getNGSampleResult(e,sr);
return sr;
sr.sampleEnd();
sr.setSuccessful(true);
sr.setResponseCodeOK();
sr.setResponseMessageOK();
sr.setResponseData(responseStr,"UTF-8");
sr.setDataType(SampleResult.TEXT);
return sr;
这是测试计划
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.1">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Parameter" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="env_test_date" elementType="Argument">
<stringProp name="Argument.name">env_test_date</stringProp>
<stringProp name="Argument.value">20130202</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="env_test_case" elementType="Argument">
<stringProp name="Argument.name">env_test_case</stringProp>
<stringProp name="Argument.value">Run at the same time</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="env_test_filesize" elementType="Argument">
<stringProp name="Argument.name">env_test_filesize</stringProp>
<stringProp name="Argument.value">1M</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="env_test_thread" elementType="Argument">
<stringProp name="Argument.name">env_test_thread</stringProp>
<stringProp name="Argument.value">2users</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="ULDLtest" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="loop controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">-1</intProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">2</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<longProp name="ThreadGroup.start_time">1358319600000</longProp>
<longProp name="ThreadGroup.end_time">1358328499000</longProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">300</stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java DL BLOB Request" enabled="true">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="SQL_TEXT" elementType="Argument">
<stringProp name="Argument.name">SQL_TEXT</stringProp>
<stringProp name="Argument.value">select * from t_download_file_data t where t.file_id='testdata1M.csv'</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DB_USER" elementType="Argument">
<stringProp name="Argument.name">DB_USER</stringProp>
<stringProp name="Argument.value">xxxx</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="USER_PWD" elementType="Argument">
<stringProp name="Argument.name">USER_PWD</stringProp>
<stringProp name="Argument.value">xxxx</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="SID" elementType="Argument">
<stringProp name="Argument.name">SID</stringProp>
<stringProp name="Argument.value">xxxxx</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="DBSERVER_IP" elementType="Argument">
<stringProp name="Argument.name">DBSERVER_IP</stringProp>
<stringProp name="Argument.value">xxx.xx.xx.xx</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PORT" elementType="Argument">
<stringProp name="Argument.name">PORT</stringProp>
<stringProp name="Argument.value">1521</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="classname">sample.TestSamplerClient</stringProp>
</JavaSampler>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="Reust for table" enabled="false">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="Result for graph" enabled="false">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>true</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename">log\ULDLPerformance_$env_test_case_$env_test_thread_$env_test_filesize_$env_test_date.jtl</stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
【问题讨论】:
你能展示你的代码和测试计划吗? 数据库在等待什么?系统 I/O 是否受限? 您好,@PMDUBIK-INGENIERIE。我已经展示了我的代码和测试计划。 你好,@JustinCave。我在测试时没有人同时使用服务器。我用 nmon 记录了性能日志,似乎没有 I/O 绑定..跨度> 【参考方案1】:当您编码时您正在测量: - 连接到数据库 - blob 读取 - 连接关闭
您可以使用 JDBC 配置元素:
http://jmeter.apache.org/usermanual/component_reference.html#JDBC_Connection_Configuration
这样在您采样之前就建立了连接。
然后通过查看 jdbc 请求如何工作以访问数据库连接来修改您的代码:
conn = DataSourceElement.getConnection("Variable Name used in JDBC_Connection_Configuration");
【讨论】:
您好,@PMDUBIK-INGENIERIE。谢谢您的回答。我正在尝试使用 JDBC 配置元素建立连接,然后从我的 java 代码中获取 blob 数据,但我找不到Java Code中获取JDBC Configuration创建的连接变量的方式。看来JavaSamplerContext只能获取String变量。 我更新了答案,如果你觉得OK,别忘了接受和投票:-) 你好,@PMDUBIK-INGENIERIE。我正在尝试再次进行测试,而我现在无法使用数据库,因为其他人正在使用它。谢谢您的想法!【参考方案2】:只要硬件足够,Oracle 数据库可以扩展到数十万并发用户。因此,您看到的结果要么是由于硬件的限制,要么是由于您编写程序的方式存在缺陷。
例如,如果您的服务器只有一个核心,那么它一次只能做一件事。因此,两个用户运行它需要两倍的时间。并不是说这就是实际发生的事情,只是说明它可能发生的事情。
【讨论】:
你好 APC。谢谢你的回答。服务器有四个核心,当我做测试时,没有人同时使用服务器。当我改变获取 blob 数据的方式时(不是逐字节,而是有缓冲区),一个用户的响应时间更短。但是两个用户同时获取blob数据,响应时间几乎变成了两倍。以上是关于从 oracle 获取 blob 数据时的限制的主要内容,如果未能解决你的问题,请参考以下文章
如何从 HDFS 获取和查看 oracle BLOB (Image) 数据到本地系统?
直接从前端将数据上传到 Azure Blob 存储时的安全问题