使用 Node.js 将超过 1m 的记录从 SQL 服务器流式传输到 MongoDB
Streaming over 1m records from SQL Server to MongoDB using Node.js
我正在尝试将 8,000,000 行数据从 Microsoft SQL 服务器复制到 MongoDB。它适用于 100,000 条记录,但是当我尝试提取 1,000,000 条记录(或全部)时,出现以下错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
这是我目前使用的代码 (Coffeescript):
MsSqlClient = require 'mssql'
MongoClient = require('mongodb').MongoClient
config = {}
config.mongodb = 'mongodb://localhost:27017/dbname'
config.mssql = 'mssql://user::pass@host/dbname'
Promise.all(
[
MongoClient.connect config.mongodb
MsSqlClient.connect config.mssql
]
).then (a) ->
mongo = a[0]
sql = a[1]
collection = mongo.collection "collection_name"
request = new MsSqlClient.Request()
request.stream = true
request.on 'row', (row) ->
collection.insert(row)
request.on 'done', (affected) ->
console.log "Completed"
sql.on 'error', (err) ->
console.log err
console.log "Querying"
request.query("SELECT * FROM big_table")
.catch (err) ->
console.log "ERROR: ", err
似乎写入 MongoDB 的时间比从 SQL 服务器下载的时间要长,我认为这是造成瓶颈的原因。有没有办法减慢 (pause/resume) 来自 SQL 服务器的流,这样我就可以在不在 SQL 数据中添加索引列并按行号选择的情况下分块拉取和写入?
运行:
- Windows7,SQL服务器 2012(SP1),MongoDB2.8.0
- Node.js4.2.4/mssql 3.3.0/mongodb2.1.19
您可以分块进行(例如 50'000)。这是一种方法(仅 SQL 侧)如何做到这一点(不是超快但应该有效):
首先获取块,这些数字你必须在 SQL:
之外循环
-- get blocks
select count(*) / 50000 as NumberOfBlocksToLoop
from YOUR.TABLE
获取块,其中 ColumnU 是允许您对 table 进行排序的列(或者,您可以直接使用 ID,但是如果从中删除数据,您可能会遇到间隙问题table):
-- get first n-block
declare @BlockNumber int
set @BlockNumber = 1
select ColumnX
from
(
select row_number() over (order by ColumnU asc) as RowNumber,
TABLE.ColumnX
from YOUR.TABLE
) Data
where RowNumber between ((@BlockNumber - 1) * 50000) + 1 and @BlockNumber * 50000
尝试为您的块找到合适的大小(当然取决于您的系统)以避免再次出现 运行 内存不足异常。您应该捕获异常,然后根据您的努力,删除已经传输的数据或计算更小的块大小(有点困难)并继续传输其余部分。
我正在尝试将 8,000,000 行数据从 Microsoft SQL 服务器复制到 MongoDB。它适用于 100,000 条记录,但是当我尝试提取 1,000,000 条记录(或全部)时,出现以下错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
这是我目前使用的代码 (Coffeescript):
MsSqlClient = require 'mssql'
MongoClient = require('mongodb').MongoClient
config = {}
config.mongodb = 'mongodb://localhost:27017/dbname'
config.mssql = 'mssql://user::pass@host/dbname'
Promise.all(
[
MongoClient.connect config.mongodb
MsSqlClient.connect config.mssql
]
).then (a) ->
mongo = a[0]
sql = a[1]
collection = mongo.collection "collection_name"
request = new MsSqlClient.Request()
request.stream = true
request.on 'row', (row) ->
collection.insert(row)
request.on 'done', (affected) ->
console.log "Completed"
sql.on 'error', (err) ->
console.log err
console.log "Querying"
request.query("SELECT * FROM big_table")
.catch (err) ->
console.log "ERROR: ", err
似乎写入 MongoDB 的时间比从 SQL 服务器下载的时间要长,我认为这是造成瓶颈的原因。有没有办法减慢 (pause/resume) 来自 SQL 服务器的流,这样我就可以在不在 SQL 数据中添加索引列并按行号选择的情况下分块拉取和写入?
运行:
- Windows7,SQL服务器 2012(SP1),MongoDB2.8.0
- Node.js4.2.4/mssql 3.3.0/mongodb2.1.19
您可以分块进行(例如 50'000)。这是一种方法(仅 SQL 侧)如何做到这一点(不是超快但应该有效):
首先获取块,这些数字你必须在 SQL:
之外循环 -- get blocks
select count(*) / 50000 as NumberOfBlocksToLoop
from YOUR.TABLE
获取块,其中 ColumnU 是允许您对 table 进行排序的列(或者,您可以直接使用 ID,但是如果从中删除数据,您可能会遇到间隙问题table):
-- get first n-block
declare @BlockNumber int
set @BlockNumber = 1
select ColumnX
from
(
select row_number() over (order by ColumnU asc) as RowNumber,
TABLE.ColumnX
from YOUR.TABLE
) Data
where RowNumber between ((@BlockNumber - 1) * 50000) + 1 and @BlockNumber * 50000
尝试为您的块找到合适的大小(当然取决于您的系统)以避免再次出现 运行 内存不足异常。您应该捕获异常,然后根据您的努力,删除已经传输的数据或计算更小的块大小(有点困难)并继续传输其余部分。