如何提高activejdbc的启动性能?
How to improve activejdbc startup performance?
我的组织在我们的 java 网络应用程序中使用带有 javalite + activejdbc 的遗留组件作为 ORM。我正在为开发创建一个本地 docker 数据库 (oracle 12c)。当我启动指向本地数据库的本地码头服务器时,启动时间超过 1 小时。原因是活跃的 jdbc 正在查看所有实体 class 的所有 table 并在循环中为每个实体获取元数据。查看活动 JDBC 注册表 class (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 秒,并且有数百个实体 classes。当我将我的本地服务器指向我们的测试数据库时,它的速度要快得多(但仍然很慢)。无论如何我可以调整我的本地 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 taking forever:
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 开发人员中 运行 时,我的 sysdba 用户需要 0.5 秒,但其他用户需要 16 秒。仍在调查这些用户之间的区别。
进一步更新...
这似乎是由于 12c 中的一些 oracle 错误。 select * 来自 all_tab_columns 当 运行 以普通用户身份使用时,执行计划有误。它抱怨一些晦涩难懂的 table “X$KZSRO” 进行完整的 table 扫描并永远排序(table 有 2 行 ffs)。当我以 sysdba 身份连接时,它 运行s 更快。我猜普通用户访问这个 table 有一些问题。现在,因为这只是开发数据库,所以我将向我的用户授予 sysdba 角色,稍后再找出一些 sql 配置文件。我知道它不是很好的解决方案,但它修复了 oracle 中的性能错误。启动时间从 1 小时缩短到 1 分钟。
首先,如果从数据库中获取元数据每 table 需要 15 到 30 秒,那一定有什么地方非常错误 与该数据库。 ActiveJDBC 使用动态发现以便在每次启动时与数据库同步。这是默认行为。
不过,如果你愿意,你可以使用Static Metadata Generation。
使用此方法,将在构建期间收集所有数据库元数据,并将作为文件打包到您的 jar 中。然后 ActiveJDBC 将立即在所有其他环境中启动,因为它将从该文件而不是数据库中读取元数据。
显然,您必须确保构建时的数据库与您的其他数据库具有完全相同的模式。否则,您将遇到一些映射问题。
虽然静态元数据生成将解决您的启动性能问题,但您的数据库仍然存在问题,我强烈建议您调查一下。
注意:ActiveJDBC 的第一个实现是在 2009 年为 Humana 实现的,我们也使用了 Oracle 数据库。我们当时的架构大约需要 120 table 秒,而且 ActiveJDBC 始终以闪电般的速度启动。
这个问题实际上不是 activejdbc 问题,而是 oracle 12c 问题。似乎从 12c 上的 ALL_TAB_COLUMNS table 读取性能不佳/查询计划不佳,除非您以 sysdba 身份登录。它并不是一个很好的解决方案,但它适用于本地 docker 开发数据库,所以我只是将我的用户设置为 sysdba。总有一天会找到一些 sql 配置文件作为真正的解决方案。 sysdba 不能用于任何产品环境,但它适合我用于本地主机开发数据库。
grant sysdba to my_user;
码头-env.xml:
<New class="oracle.jdbc.pool.OracleDataSource">
<Set name="URL">jdbc:oracle:thin:@localhost:1521/ORCLCDB.localdomain</Set>
<Set name="user">my_user as sysdba</Set>
<Set name="password">my_password</Set>
</New>
我的组织在我们的 java 网络应用程序中使用带有 javalite + activejdbc 的遗留组件作为 ORM。我正在为开发创建一个本地 docker 数据库 (oracle 12c)。当我启动指向本地数据库的本地码头服务器时,启动时间超过 1 小时。原因是活跃的 jdbc 正在查看所有实体 class 的所有 table 并在循环中为每个实体获取元数据。查看活动 JDBC 注册表 class (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 秒,并且有数百个实体 classes。当我将我的本地服务器指向我们的测试数据库时,它的速度要快得多(但仍然很慢)。无论如何我可以调整我的本地 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 taking forever:
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 开发人员中 运行 时,我的 sysdba 用户需要 0.5 秒,但其他用户需要 16 秒。仍在调查这些用户之间的区别。
进一步更新... 这似乎是由于 12c 中的一些 oracle 错误。 select * 来自 all_tab_columns 当 运行 以普通用户身份使用时,执行计划有误。它抱怨一些晦涩难懂的 table “X$KZSRO” 进行完整的 table 扫描并永远排序(table 有 2 行 ffs)。当我以 sysdba 身份连接时,它 运行s 更快。我猜普通用户访问这个 table 有一些问题。现在,因为这只是开发数据库,所以我将向我的用户授予 sysdba 角色,稍后再找出一些 sql 配置文件。我知道它不是很好的解决方案,但它修复了 oracle 中的性能错误。启动时间从 1 小时缩短到 1 分钟。
首先,如果从数据库中获取元数据每 table 需要 15 到 30 秒,那一定有什么地方非常错误 与该数据库。 ActiveJDBC 使用动态发现以便在每次启动时与数据库同步。这是默认行为。
不过,如果你愿意,你可以使用Static Metadata Generation。 使用此方法,将在构建期间收集所有数据库元数据,并将作为文件打包到您的 jar 中。然后 ActiveJDBC 将立即在所有其他环境中启动,因为它将从该文件而不是数据库中读取元数据。
显然,您必须确保构建时的数据库与您的其他数据库具有完全相同的模式。否则,您将遇到一些映射问题。
虽然静态元数据生成将解决您的启动性能问题,但您的数据库仍然存在问题,我强烈建议您调查一下。
注意:ActiveJDBC 的第一个实现是在 2009 年为 Humana 实现的,我们也使用了 Oracle 数据库。我们当时的架构大约需要 120 table 秒,而且 ActiveJDBC 始终以闪电般的速度启动。
这个问题实际上不是 activejdbc 问题,而是 oracle 12c 问题。似乎从 12c 上的 ALL_TAB_COLUMNS table 读取性能不佳/查询计划不佳,除非您以 sysdba 身份登录。它并不是一个很好的解决方案,但它适用于本地 docker 开发数据库,所以我只是将我的用户设置为 sysdba。总有一天会找到一些 sql 配置文件作为真正的解决方案。 sysdba 不能用于任何产品环境,但它适合我用于本地主机开发数据库。
grant sysdba to my_user;
码头-env.xml:
<New class="oracle.jdbc.pool.OracleDataSource">
<Set name="URL">jdbc:oracle:thin:@localhost:1521/ORCLCDB.localdomain</Set>
<Set name="user">my_user as sysdba</Set>
<Set name="password">my_password</Set>
</New>