问题描述
已使用typeorm在typescript中编写了数据库初始化脚本。而且我似乎造成了内存问题,但我想不出办法解决。
当前,脚本导入了三个文件 个人资料(55条记录) 用户(5306条记录) 登录(1006909条记录)
重写调用,因此在所有情况下,脚本都会创建一个包含所有更新的JSON,然后使用createQueryBuilder
来执行更新,如下所示:
getConnection()
.createQueryBuilder()
.insert()
.into(EULogin)
.values(loginChunk)
.execute()
.catch(error => console.log(error))
为第一个创造一个魅力,但是当涉及到最后一个(整个1,000,000个)时,它不会打球。而且我遇到了内存问题
登录:在155 MS中将196000/1006909(块大小:500)提交到数据库 登录:在823 MS中将196500/1006909(区块大小:500)提交到数据库
[60698:0x110008000] 34328 ms:清除1389.1(1423.6)-> 1388.6 (1423.6)MB,12.1 / 0.0毫秒(平均亩= 0.104,当前亩= 0.099) 分配失败[60698:0x110008000] 34339毫秒:清除1389.3 (1423.6)-> 1388.9(1423.6)MB,10.4 / 0.0毫秒(平均亩= 0.104, 当前亩= 0.099)分配失败[60698:0x110008000] 34361 毫秒:Scavenge 1389.4(1423.6)-> 1389.1(1424.1)MB,12.5 / 0.0毫秒 (平均亩= 0.104,当前亩= 0.099)分配失败
==== JS堆栈跟踪======================================== =
0: ExitFrame [pc: 0x20ed7445be3d] 1: StubFrame [pc: 0x20ed7440d608] 2: StubFrame [pc: 0x20ed7502c4cc] Security context: 0x0fbfb411e6e9 <JSObject> 3: /* anonymous */(aka /* anonymous */) [0xfbf79c62a41] [/Users/bengtbjorkberg/Development/EUGrapherNode/node_modules/typeorm/query-builder/InsertQueryBuilder.js:348]
[bytecode = 0xfbf93b851a1 offset = 26](this = 0x0fbfab4826f1 ,valueSet = 0x0fbf8846ebc1
致命错误:接近堆限制分配的无效标记压缩 失败-JavaScript堆内存不足1:0x10003cf99 node :: Abort() [/ usr / local / bin / node] 2:0x10003d1a3 node :: OnFatalError(char const *, char const *)[/ usr / local / bin / node] 3:0x1001b7835 v8 :: internal :: V8 :: FatalProcessOutOfMemory(v8 :: internal :: Isolate *,char const *,bool)[/ usr / local / bin / node] 4:0x100585682 v8 :: internal :: Heap :: FatalProcessOutOfMemory(char const *) [/ usr / local / bin / node] 5:0x100588155 v8 :: internal :: Heap :: CheckInvalidMarkCompact(无符号长整数,双精度) [/ usr / local / bin / node] 6:0x100583fff v8 :: internal :: Heap :: PerformGarbageCollection(v8 :: internal :: GarbageCollector, v8 :: GCCallbackFlags)[/ usr / local / bin / node] 7:0x1005821d4 v8 :: internal :: Heap :: CollectGarbage(v8 :: internal :: AllocationSpace, v8 :: internal :: GarbageCollectionReason,v8 :: GCCallbackFlags) [/ usr / local / bin / node] 8:0x10058ea6c v8 :: internal :: Heap :: AllocateRawWithLigthRetry(int, v8 :: internal :: AllocationSpace,v8 :: internal :: AllocationAlignment) [/ usr / local / bin / node] 9:0x10058eaef v8 :: internal :: Heap :: AllocateRawWithRetryOrFail(int, v8 :: internal :: AllocationSpace,v8 :: internal :: AllocationAlignment) [/ usr / local / bin / node] 10:0x10055e434 v8 :: internal :: Factory :: NewFillerObject(int,bool, v8 :: internal :: AllocationSpace)[/ usr / local / bin / node] 11:0x1007e6714 v8 :: internal :: Runtime_AllocateInNewSpace(int,v8 :: internal :: Object **, v8 :: internal :: Isolate *)[/ usr / local / bin / node] 12:0x20ed7445be3d
以退出代码134(被信号6:SIGABRT中断)结束的过程
我试图以同步模式(不是异步)打开数据库 我试图一次将最近的更新分成50条记录 我什至尝试打开和关闭每个块的数据库,但是死了,因为我无法使其同步执行。
使用以下方法打开数据库
:createConnection().then(connection => {
下面是“ Chunkloader”
.on('end',() => {
let compTime: number = new Date().getTime()
console.log("LOGIN: Entities read: " + loginReadCounter + " in " + new Date(compTime - loginStartTime).getMilliseconds() + " MS")
let currentChunk :number = 0;
let chunkSize : number = 500;
let loginChunk = [];
let loginStartChunkTime : number = compTime;
loginEntries.forEach(entry => {
loginChunk.push(entry);
currentChunk ++;
loginCommitCounter++;
if (currentChunk === chunkSize !! ){
getConnection()
.createQueryBuilder()
.insert()
.into(EULogin)
.values(loginChunk)
.execute()
.catch(error => console.log(error))
let compTime: number = new Date().getTime()
console.log("LOGIN: Committed " + loginCommitCounter + "/" + loginReadCounter + " (Chunk Size:" + loginChunk.length + ") to database in " + new Date(compTime - loginStartChunkTime).getMilliseconds() + " MS");
currentChunk = 0;
loginStartChunkTime = compTime;
loginChunk = [];
}
});
有什么想法吗?
=========================编辑好输入后================== ===
要尝试整理自己的头脑,我将其移至单独的函数中,我使await
正常工作,但是如何在调用后阻止该过程继续进行。因为await在createConnection内有效,但在createConnection上无效,因此该函数将立即返回
function syncDataWrite(dbEntitiy,dataSet){
console.log("DBLOADER Started for: " + dataSet.length);
createConnection().then(async connection => {
console.log("DBLOADER Connected!");
const completion = await createQueryBuilder()
.insert()
.into(dbEntitiy)
.values(dataSet)
.execute()
.catch(error => console.log(error))
console.log("DBLOADER SQL uploaded")
})
// console.log(dbEntity);
}
解决方法
您的代码建议,在对事物进行分块处理时,您将并行执行一切,这可能不是您想要的。
我建议您重写此代码以使其正确顺序。
到目前为止,最简单的方法是切换到异步/等待并使用常规的for
循环。假设.execute()
返回了一个承诺,这看起来像这样:
const connection = getConnection();
for (const entry of loginEntries) {
// [snip]
await createQueryBuilder()
.insert()
.into(EULogin)
.values(loginChunk)
.execute()
// [snip]
}
我剥离了很多代码,但我希望这种常规设置仍然有意义。
无需异步/等待就可以执行此操作,但是看起来要复杂得多。
根据您的修改进行编辑。
这是syncDataWrite
的重写版本:
async function syncDataWrite(dbEntitiy,dataSet){
console.log("DBLOADER Started for: " + dataSet.length);
const connection = await createConnection();
console.log("DBLOADER Connected!");
const completion = await createQueryBuilder()
.insert()
.into(dbEntitiy)
.values(dataSet)
.execute();
}
请注意,如果您多次使用syncDataWrite
,每个块使用1,则在调用await
syncDataWrite时仍需要CREATE TABLE BASE_TABLE AS
(
SELECT
ACT_DESC_,QTY AS EXCAVATION_QTY,APP_DATE AS EXCAVATION_APP_DATE,DOC_NO AS EXCAVATION_DOC_NO,QTY AS FORM_WORK_COMP_QTY,APP_DATE AS FORM_WORK_COMP_APP_DATE,DOC_NO AS FORM_WORK_COMP_DOC_NO,FROM
SOURCE_TABLE --this is the original table,or the table from the first image
WHERE 0=1 --this clause condition is used to create an empty table
);
。