如何使用 JDBC 有效地 export/import 数据库数据
How to efficiently export/import database data with JDBC
我有一个 JAVA 应用程序,可以使用来自任何供应商的 SQL 数据库。现在我们已经测试了 Vertica 和 PostgreSQL。我想从数据库中的一个 table 中导出所有数据,然后在应用程序的不同实例中导入它。数据库的大小很大,所以里面有很多行。必须从 java 代码内部完成导出和导入过程。
到目前为止我们已经尝试过的是:
- 导出:我们通过 JDBC 读取整个 table (
select * from
),然后将其转储到包含所有需要的 INSERTS 的 SQL 文件中。
- 导入:通过JDBC.
在目标数据库中执行包含那几千条INSERTS的文件
这不是一个有效的过程。首先,select * from
部分因为它的大小给我们带来了问题,其次,如果一个接一个地插入会给我们在 Vertica 中带来问题 (https://forum.vertica.com/discussion/235201/vjdbc-5065-error-too-many-ros-containers-exist-for-the-following-projections)
执行此操作的更有效方法是什么?是否有任何工具可以帮助完成该过程,或者没有 "elegant" 解决方案?
我只能说PostgreSQL
如果您通过在语句中使用大于 0(可能是 10000)的值调用 setFetchSize
来使用服务器端游标,SELECT
的大小不是问题。
如果
,INSERTS
会表现良好
你运行他们都在一次交易中
您使用 PreparedStatement
作为 INSERT
为什么不通过批处理(为了性能)和分块(为了避免错误并提供失败后从哪里开始的检查点)一步完成 export/import。
在大多数情况下,数据库支持 INSERT
具有多个值的查询,例如:
INSERT INTO table_a (col_a, col_b, ...) VALUES
(val_a, val_b, ...),
(val_a, val_b, ...),
(val_a, val_b, ...),
...
您在单个这样的 INSERT
语句中生成的行数就是您的块大小,这可能需要针对特定的目标数据库进行调整(大到足以加快速度但又小到足以使块不超过某些数据库限制并创建失败)。
正如已经提议的那样,每个块都应该在一个事务中执行,你的应用程序应该记住它最后成功执行了哪个块,以防出现错误,这样它就可以继续在下一个运行那里。
对于块本身,你真的应该使用 LIMIT OFFSET 。
这样,您可以随时重复任何块,每个块本身都是原子的,它应该比单行语句执行得更好。
每次插入 Vertica 都会进入 WOS(内存),并且定期将来自 WOS 的数据移动到 ROS(磁盘)到单个容器中。每个节点每个投影只能有 1024 个 ROS 容器。一次执行数千个 INSERT 对 Vertica 来说从来都不是一个好主意。执行此操作的最佳方法是将所有数据复制到一个文件中,然后使用 COPY
命令将该文件批量加载到 Vertica 中。
这将为文件内容创建一个 ROS 容器。根据您要复制的行数,它会快很多倍(有时甚至数百倍)。
我有一个 JAVA 应用程序,可以使用来自任何供应商的 SQL 数据库。现在我们已经测试了 Vertica 和 PostgreSQL。我想从数据库中的一个 table 中导出所有数据,然后在应用程序的不同实例中导入它。数据库的大小很大,所以里面有很多行。必须从 java 代码内部完成导出和导入过程。
到目前为止我们已经尝试过的是:
- 导出:我们通过 JDBC 读取整个 table (
select * from
),然后将其转储到包含所有需要的 INSERTS 的 SQL 文件中。 - 导入:通过JDBC. 在目标数据库中执行包含那几千条INSERTS的文件
这不是一个有效的过程。首先,select * from
部分因为它的大小给我们带来了问题,其次,如果一个接一个地插入会给我们在 Vertica 中带来问题 (https://forum.vertica.com/discussion/235201/vjdbc-5065-error-too-many-ros-containers-exist-for-the-following-projections)
执行此操作的更有效方法是什么?是否有任何工具可以帮助完成该过程,或者没有 "elegant" 解决方案?
我只能说PostgreSQL
如果您通过在语句中使用大于 0(可能是 10000)的值调用 setFetchSize
来使用服务器端游标,SELECT
的大小不是问题。
如果
,INSERTS
会表现良好
你运行他们都在一次交易中
您使用
PreparedStatement
作为INSERT
为什么不通过批处理(为了性能)和分块(为了避免错误并提供失败后从哪里开始的检查点)一步完成 export/import。
在大多数情况下,数据库支持 INSERT
具有多个值的查询,例如:
INSERT INTO table_a (col_a, col_b, ...) VALUES
(val_a, val_b, ...),
(val_a, val_b, ...),
(val_a, val_b, ...),
...
您在单个这样的 INSERT
语句中生成的行数就是您的块大小,这可能需要针对特定的目标数据库进行调整(大到足以加快速度但又小到足以使块不超过某些数据库限制并创建失败)。
正如已经提议的那样,每个块都应该在一个事务中执行,你的应用程序应该记住它最后成功执行了哪个块,以防出现错误,这样它就可以继续在下一个运行那里。
对于块本身,你真的应该使用 LIMIT OFFSET 。
这样,您可以随时重复任何块,每个块本身都是原子的,它应该比单行语句执行得更好。
每次插入 Vertica 都会进入 WOS(内存),并且定期将来自 WOS 的数据移动到 ROS(磁盘)到单个容器中。每个节点每个投影只能有 1024 个 ROS 容器。一次执行数千个 INSERT 对 Vertica 来说从来都不是一个好主意。执行此操作的最佳方法是将所有数据复制到一个文件中,然后使用 COPY
命令将该文件批量加载到 Vertica 中。
这将为文件内容创建一个 ROS 容器。根据您要复制的行数,它会快很多倍(有时甚至数百倍)。