【发布时间】:2021-10-04 00:39:28
【问题描述】:
我的组织在我们的 Java Web 应用程序中使用带有 javalite + activejdbc 的遗留组件作为 ORM。我正在为开发创建一个本地 docker 数据库(oracle 12c)。当我启动指向本地数据库的本地码头服务器时,启动需要 1 个多小时。原因是活动的 jdbc 正在查看所有表的所有实体类,并在循环中为每个表获取元数据。查看活动的 JDBC 注册表类 (org.javalite.activejdbc.Registry) 它这样做:
Connection c = ConnectionsAccess.getConnection(dbName);
java.sql.DatabaseMetaData databaseMetaData = c.getMetaData();
String[] tables = metaModels.getTableNames(dbName);
for (String table : tables) {
ResultSet rs = databaseMetaData.getColumns(null, schema, tableName, null);
...
}
每个调用都需要大约 15-30 秒,并且有数百个实体类。当我将本地服务器指向我们的测试数据库时,它的速度要快得多(但仍然非常慢)。无论如何我可以调整我的本地 docker 数据库,以便这些元数据调用更快?或者我可以设置任何activejdb配置来使初始化变得懒惰?与我们的测试数据库相比,这些调用在本地数据库上花费的时间要长得多,这一定是有原因的。我不认为这是因为我们的测试数据库如此强大 - 测试数据库真的很慢而且资源很少。
编辑/澄清: 这似乎不是一个活跃的 jdbc 问题,而是一个问题,为什么元数据查询在我的本地 docker 数据库上需要这么长时间。以下代码使用本地数据库 URL 需要 16 秒,指向测试时需要 356 毫秒。我还可以在 docker 映像中看到本地 CPU 峰值达到 100%。
public class DatabaseMetaDataTest {
public static void main(String args[]) throws SQLException {
//Registering the Driver
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
//Getting the connection
String url = "jdbc:oracle:thin:@localhost:1521/ORCLCDB.localdomain";
//String url = "jdbc:oracle:thin:@test:1532:xe";
Connection con = DriverManager.getConnection(url, "user", "pass");
System.out.println("Connection established......");
//Retrieving the meta data object
DatabaseMetaData metaData = con.getMetaData();
//Retrieving the columns in the database
long start = System.currentTimeMillis();
ResultSet columns = metaData.getColumns(null, "SCHEMA", "TABLE", null);
long end = System.currentTimeMillis();
System.out.println("duration:" + (end-start));
//Printing the column name and size
}
}
进一步更新: 我反编译了 oracle 驱动程序,发现这是永远占用的 SQL:
SELECT NULL AS table_cat,
t.owner AS table_schem,
t.table_name AS table_name,
t.column_name AS column_name,
DECODE (t.data_type, 'CHAR', 1, 'VARCHAR2', 12, 'NUMBER', 3,
'LONG', -1, 'DATE', 93, 'RAW', -3, 'LONG RAW', -4,
'BLOB', 2004, 'CLOB', 2005, 'BFILE', -13, 'FLOAT', 6,
'TIMESTAMP(6)', 93, 'TIMESTAMP(6) WITH TIME ZONE', -101,
'TIMESTAMP(6) WITH LOCAL TIME ZONE', -102,
'INTERVAL YEAR(2) TO MONTH', -103,
'INTERVAL DAY(2) TO SECOND(6)', -104,
'BINARY_FLOAT', 100, 'BINARY_DOUBLE', 101,
'XMLTYPE', 2009,
1111)
AS data_type,
t.data_type AS type_name,
DECODE (t.data_precision, null, DECODE(t.data_type, 'NUMBER', DECODE(t.data_scale, null, 0 , 38), DECODE (t.data_type, 'CHAR', t.char_length, 'VARCHAR', t.char_length, 'VARCHAR2', t.char_length, 'NVARCHAR2', t.char_length, 'NCHAR', t.char_length, 'NUMBER', 0, t.data_length) ), t.data_precision)
AS column_size,
0 AS buffer_length,
DECODE (t.data_type, 'NUMBER', DECODE(t.data_precision, null, DECODE(t.data_scale, null, -127 , t.data_scale), t.data_scale), t.data_scale) AS decimal_digits,
10 AS num_prec_radix,
DECODE (t.nullable, 'N', 0, 1) AS nullable,
NULL AS remarks,
t.data_default AS column_def,
0 AS sql_data_type,
0 AS sql_datetime_sub,
t.data_length AS char_octet_length,
t.column_id AS ordinal_position,
DECODE (t.nullable, 'N', 'NO', 'YES') AS is_nullable,
null as SCOPE_CATALOG,
null as SCOPE_SCHEMA,
null as SCOPE_TABLE,
null as SOURCE_DATA_TYPE,
'NO' as IS_AUTOINCREMENT
FROM all_tab_columns t
WHERE t.owner LIKE 'SCHEMA' ESCAPE '/'
AND t.table_name LIKE 'TABLE' ESCAPE '/'
AND t.column_name LIKE '%' ESCAPE '/'
ORDER BY table_schem, table_name, ordinal_position
我可以看到,当我在 oracle sql developer 中运行它时,我的 sysdba 用户需要 0.5 秒,但其他用户需要 16 秒。仍在调查这些用户之间的区别。
进一步更新... 这似乎是由于 12c 中的一些 oracle 错误造成的。 select * from all_tab_columns 在以普通用户身份运行时执行计划不佳。它抱怨一些晦涩的表“X$KZSRO”进行全表扫描并永远进行排序(表有 2 行 ffs)。当我以 sysdba 身份连接时,它运行得更快。我猜普通用户访问此表存在一些问题。现在,因为这只是开发数据库,我只是将 sysdba 角色授予我的用户并稍后找出一些 sql 配置文件。我知道它不是很好的解决方案,但它修复了 oracle 中的性能错误。启动时间从 1 小时缩短到 1 分钟。
【问题讨论】:
标签: oracle orm activejdbc