2016-05-20 7 views
0

Ich versuche, 8.000.000 Zeilen von Daten aus Microsoft SQL Server in MongoDB zu kopieren. Es funktioniert gut für 100.000 Datensätze, aber wenn ich versuche, eine Million Datensätze (oder alle) zu ziehen, bekomme ich folgende Fehlermeldung:Streamen von 1m Datensätzen von SQL Server zu MongoDB mit Node.js

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory

Hier ist der Code (Coffee) Ich bin derzeit mit:

MsSqlClient = require 'mssql' 
MongoClient = require('mongodb').MongoClient 

config = {} 
config.mongodb = 'mongodb://localhost:27017/dbname' 
config.mssql = 'mssql://user::[email protected]/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 

Es scheint, dass das Schreiben in MongoDB viel länger dauert als der Download von SQL Server, von dem ich glaube, dass er einen Engpass verursacht. Gibt es eine Möglichkeit, den Stream von SQL Server zu verlangsamen (pausieren/fortsetzen), sodass ich in Chunks ziehen und schreiben kann, ohne eine Indexspalte in den SQL-Daten hinzuzufügen und nach Zeilennummer zu wählen?

Running:

  • Windows 7, SQL Server 2012 (SP1), MongoDB 2.8.0
  • Node.js 4.2.4/3.3.0 mssql/mongodb 2.1.19
+2

'Prozess aus Speicher 'ist * nicht * ein Timing-Problem. Es ist offensichtlich erstickt auf die schiere Menge an Daten, die Sie auf einmal übertragen. Mach es in Chargen. –

+0

Was ist der beste Weg, um es in Chargen zu tun? Deshalb habe ich gefragt, ob ich den Stream pausieren soll (etwa alle 1000 Zeilen) und wieder aufnehmen soll, nachdem diese 1000 Datensätze auf Mongo geschrieben wurden. Oder sollte ich der SQL-Tabelle einen numerischen Index hinzufügen und gleichzeitig Zeilen nach Indexnummer 1000 ziehen (SELECT * FROM big_table WHERE id BETWEEN 1000 und 2000)? –

Antwort

0

Sie könnten es in Blöcken (zum Beispiel 50'000) machen. Hier ist eine Art und Weise (SQL-Seite nur), wie Sie es tun können (nicht super schnell, sollte aber funktionieren):

Erhalten Blöcke zuerst, diese Zahl müssen Sie eine Schleife außerhalb von SQL:

-- get blocks 

    select count(*)/50000 as NumberOfBlocksToLoop 
    from YOUR.TABLE 

den Block holen , wo ColumnU eine Spalte ist, dass Sie Ihre Tabelle sortieren können (alternativ können Sie eine ID direkt verwenden, aber dann könnten Sie das Problem der Lücken haben, wenn Daten aus der Tabelle gelöscht werden):

-- 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 

Try um eine gute Größe für Ihren Block zu finden (hängt natürlich von Ihrem System ab), um zu vermeiden, dass Int ausgeführt wird o out-of-memory-Ausnahme erneut. Sie sollten die Ausnahme abfangen und dann auf der Grundlage Ihrer Bemühungen entweder die bereits übertragenen Daten löschen oder eine kleinere Blockgröße berechnen (etwas schwieriger) und mit dem Rest fortfahren, um sie zu übertragen.