JDBC 明显快于 OCCI。我应该感到惊讶吗?

Posted

技术标签:

【中文标题】JDBC 明显快于 OCCI。我应该感到惊讶吗?【英文标题】:JDBC significantly faster than OCCI. Should I be surprised? 【发布时间】:2017-05-30 20:06:17 【问题描述】:

我对比较 OCCI(Oracle C++ 调用接口)和旧 JDBC 的性能测试感到非常惊讶。

代码如下:

#include <iostream>
#include <cstdlib>
#include <occi.h>

using namespace oracle::occi;
using namespace std;

const string username   = "system";
const string password   = "******";
const string url        = "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)))";
const string sql        = "select * from CREDITO.movtos_cuentas";

int main(int argc, char** argv) 

    cout << "Oracle Connectivity" << endl;

    Environment *env = Environment::createEnvironment(Environment::DEFAULT);
    Connection *conn = env->createConnection(username, password, url);
    Statement *stm = conn->createStatement(sql);
    ResultSet *rs = stm->executeQuery();

    unsigned long count = 0;

    while (rs->next()) 
        count++;
    

    stm->closeResultSet(rs);
    conn->terminateStatement(stm);
    env->terminateConnection(conn);
    Environment::terminateEnvironment(env);

    cout << "Registros na CREDITO.MOVTOS_CUENTAS: " << count << endl;

    return 0;

这里是 Java 代码:

package oraconnect.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class OraconnectJdbc 

    public static void main(String[] args) 
        Connection conn = null;
        Statement stm = null;
        ResultSet rs = null;

        try 
            Class.forName("oracle.jdbc.driver.OracleDriver");
            conn = DriverManager.getConnection(
                    "jdbc:oracle:thin:@127.0.0.1:1521:xe", "system", "******");
            stm = conn.createStatement();
            rs = stm.executeQuery("select * from CREDITO.movtos_cuentas");
            long count = 0;
            while (rs.next()) 
                count++;
            

            System.out.printf("Registros na CREDITO.MOVTOS_CUENTAS: %d\n", count);
         catch (Exception e) 
            e.printStackTrace();
         finally 
            if (rs != null) 
                try 
                    rs.close();
                 catch (SQLException e) 
                    //Ignore
                
            
            if (stm != null) 
                try 
                    stm.close();
                 catch (SQLException e) 
                    //Ignore
                
            
            if (conn != null) 
                try 
                    conn.close();
                 catch (SQLException e) 
                    //Ignore
                
            
        
    

执行:

C++ 版本

time LD_LIBRARY_PATH=/home/eduardo/Private/Oracle/instantclient_11_2/. ./oraconnect

Java 版本

time java -jar oraconnect-jdbc.jar -cp lib/oracle-driver-11.2.0.3.jar

C++ 结果:

real    1m29.392s
user    0m32.788s
sys     0m20.812s

Java 结果:

real    0m28.404s
user    0m12.076s
sys     0m4.236s

结论:

Java 明显快于 C++

我想知道我是否在 C++ 版本中犯了错误或使用了一些不好的做法。谁能帮我理解这个结果?

【问题讨论】:

他发布了一个问题,你无法相信接下来会发生什么! NathanOliver,结果已发布。 结论 - 你第二个运行的速度更快,因为一堆数据已经从磁盘中提取并位于 SGA 中。 为什么说“旧的 JDBC”? Oracle 通过添加新特性和性能优化不断改进其 JDBC 驱动程序。 感谢您改进问题的指导,但我希望您专注于寻找问题的解决方案,这是最重要的。我明白这足以理解并尝试回应。我们都会通过解决问题的方法获胜。 【参考方案1】:

在您测量时间时,差异是有效的。 如果您想了解它们为什么不同,则需要将整个时间分成一些部分,看看它们是相似还是不同。并了解差异的原因。 这可以通过许多不同的方法来完成,例如跟踪或采样二进制文件上的调用堆栈,在网络层执行 tcpdump 或许多其他方法。 一个非常方便的方法是在 Oracle 数据库中启用 SQL_TRACE - 在那里您可以获得很多花费时间的信息。关于启用 SQL_TRACE 的方法的一个很好的介绍是 https://oracle-base.com/articles/misc/sql-trace-10046-trcsess-and-tkprof。 这些跟踪文件包含大量数据并且难以阅读,尤其是在开始时。有几种工具(大多数称为“Profiler”)可用于处理这些文件。领先的产品(从我的角度来看)是 Method-R Profiler - 但由于这需要花钱,您可以尝试使用https://antognini.ch/2017/03/tvdxtat-4-0-beta-11/。

没有任何进一步的信息,没有人能说出性能差异的原因是什么。但是使用可用的工具,您可以识别它们。那么您要么比另一种更快地接受一种解决方案,要么修复它。

编辑: 我将提供一个例子: 除了许多其他原因之外,默认行为也有所不同: OCCI 一次获取 2 行: Accessing Oracle Database Using C++

默认情况下,预取是打开的,数据库会额外提取一个 一直排。

但是 jdbc 的结果集是 10: Database JDBC Developer's Guide - Result Set

默认情况下,当 Oracle JDBC 运行查询时,它会检索结果集 从数据库游标开始,一次 10 行。

因此,使用 OCCI 的网络往返次数可能是使用 jdbc 的 5 倍。

这只是一个例子——它可能是你观察的原因,也可能不是。可以肯定的是,您需要衡量,而不是猜测或要求猜测。

【讨论】:

谢谢马丁,我同意你的建议很好。但这是一个非常简单的测试,只有一个本地数据库连接和一个表中的简单 SELECT。令我惊讶的是,使用 OCCI(C++ 的 Oracle 解决方案),Java 比 C++ 快 3 倍。对我来说,这是一个令人惊讶的结果。 我怀疑Oracle的解决方案(OCCI)是否是一个好的解决方案。 嗨马丁,实际上当我均衡获取大小时,差异是近似的,但 JDBC 仍然优于 OCCI。 OCCI = 19s 和 JDBC = 12s。

以上是关于JDBC 明显快于 OCCI。我应该感到惊讶吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该对 API 密钥使用 Authorization 标头吗

不在 Python 中使用私有方法和函数是不好的做法吗?

连接到同一 DBMS 上的“外部”数据库

那些短小精悍的&奇葩的&令人感到惊讶的JavaScript代码----更新中

使用 lm() 进行线性回归 - 对结果感到惊讶

对小整数值矩阵上的 Matlab 秩函数的“不一致”行为感到惊讶