使用存储过程从 sql server 快速读取百万条记录,并使用 java 和 spring boot 将其写入 csv

Posted

技术标签:

【中文标题】使用存储过程从 sql server 快速读取百万条记录,并使用 java 和 spring boot 将其写入 csv【英文标题】:Quickly read million records from sql server using stored procedure and write it to csv using java and spring boot 【发布时间】:2020-02-14 16:19:17 【问题描述】:

我们有一个用于选择一百万条记录的存储过程。存储过程如下所示

CREATE PROCEDURE ABC(@CustID varchar(20))
AS
BEGIN

WITH temporaryTable as (SELECT ab,bc,... FROM Table); // a very huge select query

SELECT a,b, ..., l FROM temporaryTable OUTER JOIN(some_table1)...  union all SELECT m,n,..., z FROM temporaryTable OUTER JOIN(some_table2); // two very huge select query with union

END

我的任务是使用该存储过程获取结果,并使用 java 和 spring boot 将其写入 CSV 文件。

我已经尝试了 spring-data-jpa 的 @NamedStoredProcedureQuery 方法来获取结果并使用 opencsv 将其写入 CSV,但这太慢了。我确实使用了 setFirstResult() 和 setMaxResult() 方法,但看不到任何区别(也许这需要以不同方式配置存储过程,但不确定。) p>

现在我正在尝试使用 Spring Batch 的 StoredProcedureItemReader(仍在配置...)读取数据并使用 FlatFileItemWriter 写入 CSV,但我是新手虽然我认为这个链接(https://docs.spring.io/spring-batch/4.1.x/reference/html/scalability.html#scalability)可能会有所帮助,但不确定这是否会有所帮助。

我需要的是一个可以得到想要的结果的方向。

感谢并一如既往地感谢社区提供的任何有用的姿态!!!

【问题讨论】:

必须使用存储过程吗?如果没有,您可以将数据复制到临时表并使用 Spring Boot Batch 的任务执行器(多线程)进行块基处理? 我会对其进行重组,以便您的联合与临时表的连接分开发生。它会给你带来一个小小的性能提升(我的执行计划显示大约 8%)因为你正在寻找创建一个 csv,我会使用 BCP 和 powershell over Java 和 Spring 来做到这一点。 SELECT a,b FROM temporaryTable tt JOIN( SELECT a,b ... FROM some_table1 UNION ALL SELECT a,b ... FROM some_table2 ) st ON tt.a = st.a AND tt.b = st.b @dbbri - 我会向 DBA 尝试您的建议。至于 BCP 和 powershell 选项,我确实看过它,但它可能不适用于我的情况,因为程序预期用户将能够将程序下载为 ..exe 文件,然后在本地运行。 @TechGuy - 是的,我必须使用存储过程。如果我将数据复制到临时表中,这不会增加时间吗?在 Job 中使用基于块的处理和多线程 taskExecutor 的 Step 是我探索 Spring Batch 的兴趣所在,但直到现在我能够获得所需的结果。 复制数据不会花费太多时间。您应该尝试这种方法。 【参考方案1】:

我会改为使用 Reader->Writer 步骤,JdbcCursorItemReader 用于您的 Reader,FlatFileItemWriter 用于您的 Writer。

读者的 sql 只是您的问题中的 SELECT。 Writer 将使用 DelimitedLineAggregator 创建您的 CSV 输出。

【讨论】:

嗨,Dean,感谢您提出这种方法,但我想改用存储过程,因为这是我们生产中使用的,从长远来看,直接使用存储过程中的 sql 将无法维护.我首先想用完存储过程,如果这不起作用,那么我将与我的 DBA 坐下来,按照@Tech Guy 上面的 cmets 中的建议制定解决方案,然后将您的方法包含在一些修改中。 另外,您可以创建一个包装您的存储过程的 ItemReader。 read() 方法可以只遍历从它返回的结果集。这将使您更好地适应框架并使可重新启动性更易于实现。

以上是关于使用存储过程从 sql server 快速读取百万条记录,并使用 java 和 spring boot 将其写入 csv的主要内容,如果未能解决你的问题,请参考以下文章

非常慢的 ExecuteNonQuery(存储过程)与使用 SQL Server Management Studio 的快速执行

访问从 SQL Server 中的 SQLCLR 存储过程返回的 SqlXml

SQL Server - 减少读取次数[关闭]

需要帮助优化 SQL Server 查询

Mysql使用存储过程快速添加百万数据

如何最有效地在 SQL Server 中插入/更新几百万行?