我正在尝试使用node/mssql运行几十万个sql更新查询。我正在尝试:
- 分别插入每条记录(如果其中一条失败,我不希望该批失败(
- 批处理查询,这样我就不会过载SQL服务器(我可以为每个查询打开一个新的连接,但如果我这样做,服务器就会爆炸(
使用我现有的代码(99%的时间都有效(,我偶尔会得到:operation timed out for an unknown reason
,我希望有人能提出修复或改进的建议。
这就是我的
try {
const sql = require("mssql");
let pool=await new sql.connect(CONFIG_OBJ)
let batchSize=1000
let queries=[
`update xxx set [AwsCoID]='10118' where [PrimaryKey]='10118-78843' IF @@ROWCOUNT=0 insert into xxx([AwsCoID]) values('10118')`,
`update or insert 2`,
`update or insert 3`,....]
for (let i = 0; i < queries.length; i += batchSize) {
let prom = queries
.slice(i, i + batchSize)
.map((qq) => pool.request().query(qq));
for (let p of await (Promise as any).allSettled(prom)) {
//make sure connection is still active after batch finishes
pool=await new sql.connect(cc)
//console.error(`promerr:`, p);
let status: "fulfilled" | "rejected" = p.status;
let value = p.value as SqlResult;
if (status != "fulfilled" || !value.isSuccess) {
console.log(`batchRunSqlCommands() promERR:`, value);
errs.push(value);
}
}
}
} catch (e) {
console.log(`batchSqlCommand err:`, e);
} finally {
pool.close();
}
对于其他像我一样写东西的人来说,问题是SQL server在进行追加启动时会对受影响的行执行表锁定。修复方法是添加一个聚集索引,确保每个更新的记录都在自己的集群中,这样集群就会被锁定,但一次只能在集群中修改一行。
TLDR:设置一个";行唯一";列(例如PrimaryKey(作为表上的聚集索引。
这对数据库性能不好,但可以快速简单地解决问题。您也可以智能地对数据组进行集群,但在尝试再次访问之前,您需要确保您的批量更新只接触过每个集群一次并完成。