从 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=&apos;testdata1M.csv&apos;</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) 数据到本地系统?

如何获取 blob 类型的数据以在 oracle 中插入?

如何获取oracle数据库 blob 数据

直接从前端将数据上传到 Azure Blob 存储时的安全问题

python如何保存从oracle数据库中读取的BLOB文件

java 怎么读取oracle的blob类型数据,我的是保存新闻内容! 只有这么多财富值了,帮个忙谢谢