在 mssqlserver 中使用 jdbc 的 Massive Insert/Update 的最佳策略
Best strategy for Massive Insert/Update using jdbc in mssqlserver
你好,我之前发过这个问题,但好像我还不够清楚,所以我会尽量在这里详细说明我的情况。
我需要实施一个解决方案,每天从一些 CSV 文件中提取数据并仅使用 JDBC 将此数据插入生产环境数据库 tables。
我必须插入 2 tables
表格:
Table1 (
[func] [varchar](8) NOT NULL,
[Ver] [smallint] NOT NULL,
[id] [varchar](32) NOT NULL,
[desc] [varchar](300) NOT NULL,
[value] [float] NOT NULL,
[dtcreated] [date] NOT NULL,
[dtloaded] [date] NULL,
CONSTRAINT [Table1_PK] PRIMARY KEY CLUSTERED
(
[func] ASC,
[ver] ASC,
[id] ASC,
[desc] ASC,
[dtcreated] ASC
);
table2 (
[id] [varchar](32) NOT NULL,
[f1] [varchar](50) NOT NULL,
[f2] [varchar](32) NOT NULL,
[f3] [varchar](6) NULL,
[f4] [varchar](3) NULL,
[f5] [varchar](3) NULL,
[f6] [varchar](32) NULL,
[DtStart] [date] NOT NULL,
[DtEnd] [date] NOT NULL,
[dtcreated] [date] NOT NULL,
[dtloaded] [date] NULL,
CONSTRAINT [table2_PK] PRIMARY KEY CLUSTERED
(
[id] ASC,
[DtStart] DESC,
[DtEnd] DESC
)
表 1 的大小为 400+GB,有 6,500+ 百万条记录。
Table2 有 30+GB 的大小,大约有 500 万条记录。
在 table1 中,我需要处理并插入 150 万条记录。
在 table2 中,我需要处理 update/insert 110 万条记录,这是使用匹配时合并查询完成的。
我需要能够在不中断使用这些 table 的情况下执行这两个过程。
我的代码执行以下操作
public void processFile(String fileLocation) throws IOException, SQLException{
try {
SqlClient sqlClient = SqlClient.from(DriverClassName.SQLSERVER, DriverConnectionString.barra());
Connection connection = sqlClient.getConnection();
PreparedStatement pstmt = connection.prepareStatement(getSql());
File file = new File(fileLocation);
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
int lnproc = 0;
int batchCount = 0;
String line;
while (((line = br.readLine()) != null) {
String[] parts = line.split(",");
pstmt.clearParameters();
.....//Process parts and add them to the preparestatement
pstmt.addBatch();
batchCount++;
if(batchCount>=batchSize){
batchCount = 0;
try {
pstmt.executeBatch();
}catch (BatchUpdateException ex){
}
}
}
try {
pstmt.executeBatch();
}catch (BatchUpdateException ex){
}
}
connection.commit();
connection.close();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
}
}
由于要在每个 table 中插入大量记录,我可以在 table 上生成不同的锁,这会影响生产环境。
我做了一些研究,我有多种策略正在考虑使用
- 创建最多 5k 插入的批次并提交它们以防止锁定升级
- 在每条记录之后提交以防止锁定和
交易记录。
我想就您认为在这种情况下使用的最佳策略向社区征求意见。
以及您可以向我提出的任何建议。
经过调查,我找到了以下最佳解决方案,
首先如评论中所述,我读取了整个文件并将其以 java 结构加载到内存中。
加载文件后,我迭代 java 更严格并开始加载批处理中的每条记录。同时,我在添加批次的每个项目上都保留了一个计数器。
当计数器达到 5000 时,我对批次进行提交,将计数器重置为 0 并继续添加到以下项目我再次达到 5000 或到达迭代结束。
通过这样做,我阻止了 MSSQL 在 table 上创建锁,并且 table 仍然可以被其他进程和应用程序使用。
你好,我之前发过这个问题,但好像我还不够清楚,所以我会尽量在这里详细说明我的情况。
我需要实施一个解决方案,每天从一些 CSV 文件中提取数据并仅使用 JDBC 将此数据插入生产环境数据库 tables。
我必须插入 2 tables
表格:
Table1 (
[func] [varchar](8) NOT NULL,
[Ver] [smallint] NOT NULL,
[id] [varchar](32) NOT NULL,
[desc] [varchar](300) NOT NULL,
[value] [float] NOT NULL,
[dtcreated] [date] NOT NULL,
[dtloaded] [date] NULL,
CONSTRAINT [Table1_PK] PRIMARY KEY CLUSTERED
(
[func] ASC,
[ver] ASC,
[id] ASC,
[desc] ASC,
[dtcreated] ASC
);
table2 (
[id] [varchar](32) NOT NULL,
[f1] [varchar](50) NOT NULL,
[f2] [varchar](32) NOT NULL,
[f3] [varchar](6) NULL,
[f4] [varchar](3) NULL,
[f5] [varchar](3) NULL,
[f6] [varchar](32) NULL,
[DtStart] [date] NOT NULL,
[DtEnd] [date] NOT NULL,
[dtcreated] [date] NOT NULL,
[dtloaded] [date] NULL,
CONSTRAINT [table2_PK] PRIMARY KEY CLUSTERED
(
[id] ASC,
[DtStart] DESC,
[DtEnd] DESC
)
表 1 的大小为 400+GB,有 6,500+ 百万条记录。 Table2 有 30+GB 的大小,大约有 500 万条记录。
在 table1 中,我需要处理并插入 150 万条记录。
在 table2 中,我需要处理 update/insert 110 万条记录,这是使用匹配时合并查询完成的。
我需要能够在不中断使用这些 table 的情况下执行这两个过程。
我的代码执行以下操作
public void processFile(String fileLocation) throws IOException, SQLException{
try {
SqlClient sqlClient = SqlClient.from(DriverClassName.SQLSERVER, DriverConnectionString.barra());
Connection connection = sqlClient.getConnection();
PreparedStatement pstmt = connection.prepareStatement(getSql());
File file = new File(fileLocation);
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
int lnproc = 0;
int batchCount = 0;
String line;
while (((line = br.readLine()) != null) {
String[] parts = line.split(",");
pstmt.clearParameters();
.....//Process parts and add them to the preparestatement
pstmt.addBatch();
batchCount++;
if(batchCount>=batchSize){
batchCount = 0;
try {
pstmt.executeBatch();
}catch (BatchUpdateException ex){
}
}
}
try {
pstmt.executeBatch();
}catch (BatchUpdateException ex){
}
}
connection.commit();
connection.close();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
}
}
由于要在每个 table 中插入大量记录,我可以在 table 上生成不同的锁,这会影响生产环境。
我做了一些研究,我有多种策略正在考虑使用
- 创建最多 5k 插入的批次并提交它们以防止锁定升级
- 在每条记录之后提交以防止锁定和 交易记录。
我想就您认为在这种情况下使用的最佳策略向社区征求意见。
以及您可以向我提出的任何建议。
经过调查,我找到了以下最佳解决方案,
首先如评论中所述,我读取了整个文件并将其以 java 结构加载到内存中。
加载文件后,我迭代 java 更严格并开始加载批处理中的每条记录。同时,我在添加批次的每个项目上都保留了一个计数器。 当计数器达到 5000 时,我对批次进行提交,将计数器重置为 0 并继续添加到以下项目我再次达到 5000 或到达迭代结束。
通过这样做,我阻止了 MSSQL 在 table 上创建锁,并且 table 仍然可以被其他进程和应用程序使用。