Elaborazione di 1,5 milioni di file l'uno contro l'altro

c# preprocessor sqlbulkcopy sql-server-2008

Domanda

Ho bisogno di passare attraverso 1,5 milioni di righe, per la riga ho bisogno di calcolare una varianza rispetto a tutte le altre righe.

Al momento sto facendo qualcosa come:

    // Mocked Data
    var myTable = new DataTable("hello");
    myTable.Columns.Add("ID", typeof (int));
    myTable.Columns.Add("Value", typeof(byte[]));
    var random = new Random();
    for (int i = 0; i < 1000; i++)
    {
        var row = myTable.NewRow();
        row["ID"] = i;
        var bitArray = new BitArray(50 * 50);
        for (int j = 0; j < 50*50; j++)
        {
            bitArray.Set(j, random.NextDouble() >= random.NextDouble());
        }

        byte[] byteArray = new byte[(int)Math.Ceiling((double)bitArray.Length / 8)];

        bitArray.CopyTo(byteArray, 0);

        row["Value"] = byteArray;
        myTable.Rows.Add(row);
    }
    // Mocked data complete.


    var calculated = new DataTable("calculated");
    calculated.Columns.Add("ID", typeof (int));
    calculated.Columns.Add("AaginstID", typeof (int));
    calculated.Columns.Add("ComputedIntersect", typeof(byte[]));
    calculated.Columns.Add("ComputedUnion", typeof(byte[]));
    for (int i = 0; i < myTable.Rows.Count; i++)
    {
        for (int j = i + 1; j < myTable.Rows.Count; j++)
        {
            var row = calculated.NewRow();
            row["ID"] = myTable.Rows[i]["ID"];
            row["AaginstID"] = myTable.Rows[j]["ID"];

            var intersectArray = new BitArray((byte[]) myTable.Rows[i]["Value"]);
            var unionArray = new BitArray((byte[])myTable.Rows[i]["Value"]);
            var jArray = new BitArray((byte[])myTable.Rows[j]["Value"]);


            intersectArray.And(jArray);
            unionArray.Or(jArray);

            var intersectByteArray = new byte[(int)Math.Ceiling((double)intersectArray.Length / 8)];
            var unionByteArray = new byte[(int)Math.Ceiling((double)unionArray.Length / 8)];

            intersectArray.CopyTo(intersectByteArray, 0);
            unionArray.CopyTo(unionByteArray, 0);

            row["ComputedIntersect"] = intersectByteArray;
            row["ComputedUnion"] = unionByteArray;
            calculated.Rows.Add(row);
        }
        // Real data is 1.5m+ rows, so need to do this incrementally
        // STORE DATA TO DB HERE
    }

Archivia i miei dati utilizzando SQLBulkCopy con TableLock attivo, il mio BatchSize è predefinito (0 - intero batch). Il salvataggio di 1,5 milioni di record nel DB è un po 'lento (30/60 secondi), quindi sono aperto a suggerimenti su come modificare il meccanismo di archiviazione SQL, ma il collo di bottiglia principale è C #. Il mio BitArray ha una dimensione di 2500 bit (io uso 50 * 50 perché è una griglia, nel codice che ammetto per una dimensione della griglia variabile, per questo test, presumo che sia sempre 2500 bit).

Per elaborare 1,5 milioni di righe su una singola riga impiega circa 140 secondi, questo richiederebbe troppo tempo per elaborare tutto, quindi ho bisogno di trovare un modo migliore. Questo lavoro è stato fatto al fine di pre-processare i dati per un recupero più rapido quando conta, quindi potrei lasciarlo andare per un giorno, ma dai miei calcoli, ci vorranno quasi tre anni per elaborare ...

Memorizzo i dati nel DB su ciascun loop del ciclo esterno in modo da non tenere troppa memoria in una volta. I dati sono impostati in modo irrealistico, io uso BitArray.Set per il primo round di elaborazione (per generare 1,5 milioni di righe), e questo è un collo di bottiglia, ma non ha bisogno di revisione. L'obiettivo principale è quello di ottenere l'unione / intersezione di ogni fila con tutti gli altri, in modo che più avanti riesca a tirare fuori le righe correlate, pronto per partire. Quindi, se c'è un tipo di archiviazione migliore (Binary (313) nel DB), o un modo migliore per ottenere lo stesso risultato, sono aperto a una riscrittura.

Ho preso in considerazione la scrittura di una funzione CLR SQL, ma non sono sicuro che sia l'approccio giusto. È richiesta la pre-elaborazione dei dati, quindi sono in cerca di aiuto sull'approccio migliore.

Risposta popolare

Suggerirei di fare tutto il tuo calcolo nel database. SQL Server è il migliore per le operazioni basate su set che lo rende perfetto per questi tipi di problemi. Ho una breve idea dei passi che potresti compiere

  1. bcp tutti i tuoi dati in una tabella temporanea.
  2. Aggiorna la tabella temporanea con i valori calcolati necessari.
  3. Inserisci nella tua tabella "reale" selezionando i valori che desideri dalla tabella temporanea.


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché