使用Oracle jdbc进行极慢的Apache Drill查询

时间:2017-01-23 20:26:07

标签: java oracle jdbc apache-drill

我已成功使用Oracle的JDBC客户端(来自oracle的最新ojdbc7.jar)设置Apache Drill(最新版​​本1.9)作为存储插件:

{
  "type": "jdbc",
  "driver": "oracle.jdbc.driver.OracleDriver",
  "url": "jdbc:oracle:thin:@server:1521/myservicename",
  "username": "TEST_USER",
  "password": "password",
  "enabled": true
}

我可以进行查询,但即使是最简单的事情也需要几分钟才能执行。 查询单行表需要78秒。 只需设置默认架构需要一分钟:

0: jdbc:drill:zk=local> use oracle.TEST_USER
. . . . . . . . . . . > ;
+-------+-------------------------------------------------+
|  ok   |                     summary                     |
+-------+-------------------------------------------------+
| true  | Default schema changed to [oracle.TEST_USER]  |
+-------+-------------------------------------------------+
1 row selected (77,5 seconds)

但是我已经使用一个简单的hello-world风格的java应用程序进行了测试,使用相同连接字符串的连接可以正常工作,完整的表提取时间约为0.1秒。

jdbc:oracle:thin:@server:1521/myservicename

我已经从Ubuntu和Mac进行了测试,并尝试设置java的随机源,因为其他答案指出是潜在的性能问题:

export DRILL_JAVA_OPTS="$DRILL_JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"

这里发生了什么?这是一个已知问题还是有一些解决方法?

我使用了钻孔嵌入式。

2 个答案:

答案 0 :(得分:1)

我能够找到这个问题的根本原因。

问题不是慢查询,而是Drill的元数据查询中的非最佳预取策略。 就我而言,数据库非常庞大,并且每百个表都有数千个模式(oracle用户)。 oracles默认fetchsize为10,导致数百个DB往返。

每个Apache Drill JDBC查询都在检查元数据。

Apache Drill: JdbcStoragePlugin.java#L351内:

java.sql.DatabaseMetaData.getSchemas()

Apache Calcite (Drill dependency): JdbcMeta.java#L323内:

java.sql.DatabaseMetaData.getTables(...)

这两个部分都不会覆盖任何默认的fetchsize,并且通过wireshark,我可以逐字逐句地看到每个只有10行的包。 (数据库服务器的延迟非常高,位于其他地方)

我已经通过手动调用setFetchSize重新编译了Apache Drill,这大大缩短了响应时间。到目前为止,我没有对Calcite进行修补,但也可能会这样做。

总的来说,我认为在获取元数据时,应该考虑编写高性能JDBC代码的常规步骤,因为真实世界的场景很容易最终得到更大的元数据(例如,超过10个表或模式) 另一个想法是缓存,但我还没有在Drill的JDBC存储插件中看到任何元数据缓存。

答案 1 :(得分:1)

对于那些有同样问题并试图找到答案的人。

我更新了 oracle jar 文件 /oracle/jdbc/defaultConnectionProperties.properties

并添加 oracle.jdbc.defaultRowPrefetch=200

我使用 7zip 打开和编辑文件内容

注意:您需要为您的案例找到最佳的 rowPrefetch

我阅读How to fix "<string> DeprecationWarning: invalid escape sequence" in Python?是为了给我一个想法。