Vraag Verbeter de INSERT-per-seconde prestaties van SQLite?


Het optimaliseren van SQLite is lastig. Bulk-invoegprestaties van een C-toepassing kunnen variëren van 85 inserts per seconde tot meer dan 96.000 inserts per seconde!

Achtergrond: We gebruiken SQLite als onderdeel van een desktop-applicatie. We hebben grote hoeveelheden configuratiegegevens opgeslagen in XML-bestanden die worden geparseerd en in een SQLite-database worden geladen voor verdere verwerking wanneer de toepassing wordt geïnitialiseerd. SQLite is ideaal voor deze situatie omdat het snel is, geen gespecialiseerde configuratie vereist en de database als één bestand op schijf wordt opgeslagen.

Achtergrond:  Aanvankelijk was ik teleurgesteld over de prestaties die ik zag. Het blijkt dat de prestaties van SQLite aanzienlijk kunnen variëren (zowel voor bulk-invoegingen als voor selectie), afhankelijk van hoe de database is geconfigureerd en hoe u de API gebruikt. Het was geen triviale zaak om uit te zoeken wat alle opties en technieken waren, dus ik dacht dat het verstandig was om deze community-wiki-vermelding te maken om de resultaten te delen met Stack Overflow-lezers om anderen de moeite van hetzelfde onderzoek te besparen.

Het experiment: In plaats van alleen te praten over prestatietips in algemene zin (d.w.z. "Gebruik een transactie!"), Ik dacht dat het het beste was om wat C-code te schrijven en meten de impact van verschillende opties. We beginnen met enkele eenvoudige gegevens:

  • Een 28 MB TAB-gescheiden tekstbestand (ongeveer 865.000 records) van de volledige transittijdenplan voor de stad Toronto
  • Mijn testmachine is een 3.60 GHz P4 met Windows XP.
  • De code is gecompileerd met Visual C ++ 2005 als "Release" met "Volledige optimalisatie" (/ Ox) en Favor Fast Code (/ Ot).
  • Ik gebruik de SQLite "Amalgamation", direct gecompileerd in mijn testapplicatie. De SQLite-versie die ik toevallig heb is iets ouder (3.6.7), maar ik vermoed dat deze resultaten vergelijkbaar zijn met de nieuwste release (laat een reactie achter als je anders denkt).

Laten we wat code schrijven!

De code: Een eenvoudig C-programma dat het tekstbestand regel voor regel leest, splitst de tekenreeks in waarden en voegt de gegevens vervolgens in een SQLite-database in. In deze "basislijn" -versie van de code wordt de database gemaakt, maar we zullen niet echt gegevens invoegen:

/*************************************************************
    Baseline code to experiment with SQLite performance.

    Input data is a 28 MB TAB-delimited text file of the
    complete Toronto Transit System schedule/route info
    from http://www.toronto.ca/open/datasets/ttc-routes/

**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "sqlite3.h"

#define INPUTDATA "C:\\TTC_schedule_scheduleitem_10-27-2009.txt"
#define DATABASE "c:\\TTC_schedule_scheduleitem_10-27-2009.sqlite"
#define TABLE "CREATE TABLE IF NOT EXISTS TTC (id INTEGER PRIMARY KEY, Route_ID TEXT, Branch_Code TEXT, Version INTEGER, Stop INTEGER, Vehicle_Index INTEGER, Day Integer, Time TEXT)"
#define BUFFER_SIZE 256

int main(int argc, char **argv) {

    sqlite3 * db;
    sqlite3_stmt * stmt;
    char * sErrMsg = 0;
    char * tail = 0;
    int nRetCode;
    int n = 0;

    clock_t cStartClock;

    FILE * pFile;
    char sInputBuf [BUFFER_SIZE] = "\0";

    char * sRT = 0;  /* Route */
    char * sBR = 0;  /* Branch */
    char * sVR = 0;  /* Version */
    char * sST = 0;  /* Stop Number */
    char * sVI = 0;  /* Vehicle */
    char * sDT = 0;  /* Date */
    char * sTM = 0;  /* Time */

    char sSQL [BUFFER_SIZE] = "\0";

    /*********************************************/
    /* Open the Database and create the Schema */
    sqlite3_open(DATABASE, &db);
    sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);

    /*********************************************/
    /* Open input file and import into Database*/
    cStartClock = clock();

    pFile = fopen (INPUTDATA,"r");
    while (!feof(pFile)) {

        fgets (sInputBuf, BUFFER_SIZE, pFile);

        sRT = strtok (sInputBuf, "\t");     /* Get Route */
        sBR = strtok (NULL, "\t");            /* Get Branch */
        sVR = strtok (NULL, "\t");            /* Get Version */
        sST = strtok (NULL, "\t");            /* Get Stop Number */
        sVI = strtok (NULL, "\t");            /* Get Vehicle */
        sDT = strtok (NULL, "\t");            /* Get Date */
        sTM = strtok (NULL, "\t");            /* Get Time */

        /* ACTUAL INSERT WILL GO HERE */

        n++;
    }
    fclose (pFile);

    printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);

    sqlite3_close(db);
    return 0;
}

De controle"

Als de code as-is wordt uitgevoerd, worden feitelijk geen databasebewerkingen uitgevoerd, maar dit geeft ons een idee van hoe snel de onbewerkte C-bestands-I / O en tekenreeksverwerkingsbewerkingen zijn.

Ingevoerde 864913 records in 0,94   seconden

Super goed! We kunnen 920.000 inserts per seconde doen, op voorwaarde dat we geen inserts doen :-)


Het "Worst-Case-Scenario"

We gaan de SQL-reeks genereren met behulp van de waarden die uit het bestand zijn gelezen en die SQL-bewerking aanroepen met sqlite3_exec:

sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", sRT, sBR, sVR, sST, sVI, sDT, sTM);
sqlite3_exec(db, sSQL, NULL, NULL, &sErrMsg);

Dit gaat langzaam omdat de SQL wordt gecompileerd in VDBE-code voor elke invoeging en elke invoeging gebeurt in een eigen transactie. Hoe langzaam?

Ingevoerde 864913 records in 9933.61   seconden

Yikes! 2 uur en 45 minuten! Dat is alleen 85 inserts per seconde.

Een transactie gebruiken

SQLite evalueert standaard elke INSERT / UPDATE-instructie binnen een unieke transactie. Als u een groot aantal inserts uitvoert, is het raadzaam om uw transactie in een transactie in te pakken:

sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);

pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {

    ...

}
fclose (pFile);

sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);

Ingevoerde 864913 records in 38.03   seconden

Dat is beter. Het simpelweg inpakken van al onze inserts in een enkele transactie verbeterde onze prestaties tot 23.000 inserts per seconde.

Een voorbereide verklaring gebruiken

Het gebruik van een transactie was een enorme verbetering, maar het opnieuw compileren van de SQL-instructie voor elke bijlage heeft geen zin als we dezelfde SQL steeds opnieuw gebruiken. Laten we gebruiken sqlite3_prepare_v2 om onze SQL-instructie één keer te compileren en vervolgens onze parameters aan die verklaring te koppelen met sqlite3_bind_text:

/* Open input file and import into the database */
cStartClock = clock();

sprintf(sSQL, "INSERT INTO TTC VALUES (NULL, @RT, @BR, @VR, @ST, @VI, @DT, @TM)");
sqlite3_prepare_v2(db,  sSQL, BUFFER_SIZE, &stmt, &tail);

sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);

pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {

    fgets (sInputBuf, BUFFER_SIZE, pFile);

    sRT = strtok (sInputBuf, "\t");   /* Get Route */
    sBR = strtok (NULL, "\t");        /* Get Branch */
    sVR = strtok (NULL, "\t");        /* Get Version */
    sST = strtok (NULL, "\t");        /* Get Stop Number */
    sVI = strtok (NULL, "\t");        /* Get Vehicle */
    sDT = strtok (NULL, "\t");        /* Get Date */
    sTM = strtok (NULL, "\t");        /* Get Time */

    sqlite3_bind_text(stmt, 1, sRT, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, sBR, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 3, sVR, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 4, sST, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 5, sVI, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 6, sDT, -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 7, sTM, -1, SQLITE_TRANSIENT);

    sqlite3_step(stmt);

    sqlite3_clear_bindings(stmt);
    sqlite3_reset(stmt);

    n++;
}
fclose (pFile);

sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);

printf("Imported %d records in %4.2f seconds\n", n, (clock() - cStartClock) / (double)CLOCKS_PER_SEC);

sqlite3_finalize(stmt);
sqlite3_close(db);

return 0;

Geïmporteerde 864913 records in 16.27   seconden

Leuk! Er is een beetje meer code (vergeet niet te bellen sqlite3_clear_bindings en sqlite3_reset), maar we hebben onze prestaties meer dan verdubbeld tot 53.000 invoegingen per seconde.

PRAGMA synchroon = UIT

Standaard pauzeert SQLite na het schrijven van een schrijfopdracht op OS-niveau. Dit garandeert dat de gegevens naar de schijf worden geschreven. Door in te stellen synchronous = OFF, we geven SQLite de opdracht om de gegevens simpelweg aan het besturingssysteem door te geven voor schrijven en vervolgens door te gaan. Er is een kans dat het databasebestand beschadigd raakt als de computer een catastrofale crash (of stroomstoring) heeft voordat de gegevens naar de schijf worden geschreven:

/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);

Geïmporteerde 864913 records in 12.41   seconden

De verbeteringen zijn nu kleiner, maar we doen het 69.600 inserts per seconde.

PRAGMA journal_mode = MEMORY

Overweeg het rollback-journaal in het geheugen op te slaan door het te evalueren PRAGMA journal_mode = MEMORY. Uw transactie zal sneller zijn, maar als u stroom verliest of uw programma crasht tijdens een transactie, kan uw database in een corrupte staat worden achtergelaten met een gedeeltelijk voltooide transactie:

/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);

Geïmporteerde 864913 records in 13.50   seconden

Een beetje langzamer dan de vorige optimalisatie op 64.000 inserts per seconde.

PRAGMA synchroon = UIT en PRAGMA journal_mode = MEMORY

Laten we de vorige twee optimalisaties combineren. Het is een beetje riskanter (in geval van een crash), maar we importeren alleen gegevens (geen bank draaien):

/* Open the database and create the schema */
sqlite3_open(DATABASE, &db);
sqlite3_exec(db, TABLE, NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg);

Ingevoerde 864913-records in 12.00 uur   seconden

Fantastisch! We kunnen het doen 72.000 inserts per seconde.

Een in-memory database gebruiken

Gewoon voor de kick, laten we voortbouwen op alle eerdere optimalisaties en de databasebestandsnaam opnieuw definiëren, zodat we volledig in RAM werken:

#define DATABASE ":memory:"

Geïmporteerde 864913 records in 10.94   seconden

Het is niet super praktisch om onze database in RAM op te slaan, maar het is indrukwekkend dat we kunnen presteren 79.000 inserts per seconde.

C code herformuleren

Hoewel het niet specifiek een SQLite-verbetering is, vind ik de extra niet leuk char*toewijzingsoperaties in de while lus. Laten we snel die code refactoren om de uitvoer van door te geven strtok() rechtstreeks in sqlite3_bind_text(), en laat de compiler proberen de dingen sneller voor ons te maken:

pFile = fopen (INPUTDATA,"r");
while (!feof(pFile)) {

    fgets (sInputBuf, BUFFER_SIZE, pFile);

    sqlite3_bind_text(stmt, 1, strtok (sInputBuf, "\t"), -1, SQLITE_TRANSIENT); /* Get Route */
    sqlite3_bind_text(stmt, 2, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Branch */
    sqlite3_bind_text(stmt, 3, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Version */
    sqlite3_bind_text(stmt, 4, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Stop Number */
    sqlite3_bind_text(stmt, 5, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Vehicle */
    sqlite3_bind_text(stmt, 6, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Date */
    sqlite3_bind_text(stmt, 7, strtok (NULL, "\t"), -1, SQLITE_TRANSIENT);    /* Get Time */

    sqlite3_step(stmt);        /* Execute the SQL Statement */
    sqlite3_clear_bindings(stmt);    /* Clear bindings */
    sqlite3_reset(stmt);        /* Reset VDBE */

    n++;
}
fclose (pFile);

Opmerking: we zijn terug bij het gebruik van een echt databasebestand. In-memory databases zijn snel, maar niet noodzakelijkerwijs praktisch

Geïmporteerde 864913 records in 8.94   seconden

Een kleine aanpassing aan de stringverwerkingscode die in onze parameterbinding is gebruikt, heeft ons in staat gesteld om te presteren 96,700 inserts per seconde. Ik denk dat het veilig is om te zeggen dat dit zo is genoeg snel. Naarmate we andere variabelen gaan aanpassen (zoals paginaformaat, indexcreatie, etc.), zal dit onze benchmark zijn.


Samenvatting (tot nu toe)

Ik hoop dat je nog steeds bij me bent! De reden dat we deze weg zijn ingeslagen, is dat de bulk-invoegprestaties zo enorm variëren met SQLite, en het is niet altijd duidelijk welke wijzigingen moeten worden doorgevoerd om onze werking te versnellen. Met dezelfde compiler (en compiler-opties), dezelfde versie van SQLite en dezelfde gegevens hebben we onze code en ons gebruik van SQLite om te gaan geoptimaliseerd van een worst-case scenario van 85 inserts per seconde naar meer dan 96.000 inserts per seconde!


CREËER DE INDEX en vervolgens INSERT versus INSERT en CREëER INDEX

Voordat we beginnen met meten SELECT prestaties, we weten dat we indexen gaan maken. In een van de onderstaande antwoorden wordt gesuggereerd dat het bij bulk-invoegingen sneller is om de index te maken nadat de gegevens zijn ingevoegd (in tegenstelling tot het eerst maken van de index en vervolgens het invoegen van de gegevens). Laten we proberen:

Maak een index en vervolgens gegevens invoegen

sqlite3_exec(db, "CREATE  INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
...

Geïmporteerde 864913 records in 18.13   seconden

Voeg gegevens in en maak vervolgens een index aan

...
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "CREATE  INDEX 'TTC_Stop_Index' ON 'TTC' ('Stop')", NULL, NULL, &sErrMsg);

Ingevoerde 864913 records in 13,66   seconden

Zoals verwacht zijn bulk-inserts langzamer als één kolom is geïndexeerd, maar het maakt wel uit of de index wordt gemaakt nadat de gegevens zijn ingevoegd. Onze no-index baseline is 96.000 inserts per seconde. Eerst de index maken en vervolgens de gegevens invoegen, levert ons 47.700 inserts per seconde op, terwijl het invoegen van de gegevens eerst en vervolgens het maken van de index 63.300 inserts per seconde oplevert.


Ik zou graag suggesties voor andere scenario's proberen om ... En binnenkort soortgelijke gegevens voor SELECT-zoekopdrachten te compileren.


2568


oorsprong


antwoorden:


Verschillende tips:

  1. Plaats inserts / updates in een transactie.
  2. Voor oudere versies van SQLite - Overweeg een minder paranoïde dagboekmodus (pragma journal_mode). Er bestaat NORMALen dan is er OFF, wat de invoegsnelheid aanzienlijk kan verhogen als u zich niet al te veel zorgen maakt over de database die mogelijk beschadigd raakt als het besturingssysteem crasht. Als uw toepassing crasht, zou het goed moeten zijn met de gegevens. Merk op dat in nieuwere versies de OFF/MEMORY instellingen zijn niet veilig voor crashes op toepassingsniveau.
  3. Spelen met paginaformaten maakt ook een verschil (PRAGMA page_size). Als u grotere paginaformaten gebruikt, kunnen lees- en schrijfbewerkingen een beetje sneller worden als grotere pagina's in het geheugen worden opgeslagen. Merk op dat er meer geheugen wordt gebruikt voor uw database.
  4. Als u indices heeft, kunt u bellen CREATE INDEXna het doen van al uw inserts. Dit is aanzienlijk sneller dan het maken van de index en vervolgens het doen van uw inserts.
  5. Je moet heel voorzichtig zijn als je gelijktijdige toegang hebt tot SQLite, omdat de hele database is vergrendeld als schrijven klaar is, en hoewel er meerdere lezers mogelijk zijn, wordt schrijven geblokkeerd. Dit is enigszins verbeterd met de toevoeging van een WAL in nieuwere SQLite-versies.
  6. Profiteer van ruimtebesparing ... kleinere databases gaan sneller. Als u bijvoorbeeld sleutelwaardeparen hebt, probeer dan de sleutel te maken INTEGER PRIMARY KEY indien mogelijk, die de impliciete unieke rijnummerkolom in de tabel zal vervangen.
  7. Als u meerdere threads gebruikt, kunt u proberen de gedeelde pagina cache, waarmee geladen pagina's kunnen worden gedeeld tussen threads, waardoor dure I / O-oproepen kunnen worden voorkomen.
  8. Niet gebruiken !feof(file)!

Ik heb ook soortgelijke vragen gesteld hier en hier.


672



Probeer het te gebruiken SQLITE_STATIC in plaats van SQLITE_TRANSIENT voor die inserts.

SQLITE_TRANSIENT zorgt ervoor dat SQLite de stringgegevens kopieert voordat deze worden geretourneerd.

SQLITE_STATIC vertelt dat het geheugenadres dat u hebt opgegeven geldig blijft totdat de query is uitgevoerd (wat in deze lus altijd het geval is). Hiermee bespaart u verschillende toewijzingen, kopieën en de toewijzing van bewerkingen per lus. Mogelijk een grote verbetering.


102



Vermijd sqlite3_clear_bindings (stmt);

De code in de test bepaalt de bindingen telkens dat voldoende zou moeten zijn.

De C API-intro van de SQLite-documenten zegt

Voordat u sqlite3_step () voor de eerste keer of meteen belt   na sqlite3_reset () kan de toepassing een van de aanroepen   sqlite3_bind () interfaces om waarden aan de parameters te koppelen. Elk   aanroep naar sqlite3_bind () heft eerdere bindingen op dezelfde parameter op

(zien: sqlite.org/cintro.html). Er is niets in de documentatie voor die functie zeggend dat je het moet noemen, naast het eenvoudig instellen van de bindingen.

Meer detail: http://www.hoogli.com/blogs/micro/index.html#Avoid_sqlite3_clear_bindings ()


80



Op bulk-inserts

Geïnspireerd door deze post en door de Stack Overflow-vraag die me hier heeft geleid - Is het mogelijk om meerdere rijen tegelijk in een SQLite-database in te voegen? - Ik heb mijn eerste geplaatst Git repository:

https://github.com/rdpoor/CreateOrUpdate

in welke bulk een reeks ActiveRecords wordt geladen MySQL, SQLite of PostgreSQL databases. Het bevat een optie om bestaande records te negeren, ze te overschrijven of een fout te melden. Mijn rudimentaire benchmarks laten een 10x snelheidsverbetering zien in vergelijking met sequentiële schrijfbewerkingen - YMMV.

Ik gebruik het in productiecode, waar ik vaak grote datasets moet importeren, en ik ben er best tevreden mee.


47



Bulkimport lijkt het beste te presteren als u uw brokken kunt opnemen INSERT / UPDATE statements. Een waarde van 10.000 of zo heeft goed gewerkt voor mij op een tafel met slechts een paar rijen, YMMV ...


40



Als je alleen geïnteresseerd bent in lezen, iets sneller (maar mogelijk oude gegevens leest), is de versie om te lezen van meerdere verbindingen van meerdere threads (verbinding per thread).

Zoek eerst de items in de tabel:

 SELECT COUNT(*) FROM table

lees dan in pagina's (LIMIT / OFFSET)

  SELECT * FROM table ORDER BY _ROWID_ LIMIT <limit> OFFSET <offset>

waar en worden berekend per thread, zoals deze:

int limit = (count + n_threads - 1)/n_threads;

voor elke thread:

int offset = thread_index * limit

Voor onze kleine (200mb) db maakte dit een snelheid van 50-75% (3.8.0.2 64-bit op Windows 7). Onze tabellen zijn sterk niet-genormaliseerd (1000-1500 kolommen, ruwweg 100.000 of meer rijen).

Te veel of te weinig threads zullen het niet doen, je moet jezelf benchmarken en profileren.

Ook voor ons maakte SHAREDCACHE de uitvoering langzamer, dus heb ik PRIVATECACHE handmatig gezet (omdat deze wereldwijd voor ons is ingeschakeld)


32



Ik kan geen winst behalen uit transacties totdat ik cache_size verhoogde naar een hogere waarde, d.w.z. PRAGMA cache_size=10000;


20



Na het lezen van deze tutorial probeerde ik het te implementeren in mijn programma.

Ik heb 4-5 bestanden die adressen bevatten. Elk bestand heeft ongeveer 30 miljoen records. Ik gebruik dezelfde configuratie die u voorstelt maar mijn aantal INSERTs per seconde is erg laag (~ 10.000 records per seconde).

Hier is uw suggestie mislukt. U gebruikt één transactie voor alle records en één invoeging zonder fouten / mislukkingen. Laten we zeggen dat u elke record in meerdere invoegingen op verschillende tabellen splitst. Wat gebeurt er als het record is verbroken?

De opdracht ON CONFLICT is niet van toepassing, want als u 10 elementen in een record hebt en u elk element in een andere tabel moet invoegen, moet als element 5 een CONSTRAINT-fout krijgt, alle vorige 4 invoegtoepassingen ook worden gebruikt.

Dus hier is waar de terugdraaiing komt. Het enige probleem met de rollback is dat je al je inserts verliest en vanaf de top begint. Hoe kun je dit oplossen?

Mijn oplossing was om te gebruiken meerdere transacties. Ik begin en beëindig elke 10.000 records een transactie (vraag niet waarom dat nummer, het was de snelste die ik heb getest). Ik heb een array van 10.000 gemaakt en de succesvolle records daar ingevoegd. Wanneer de fout optreedt, doe ik een terugdraaiing, begin ik een transactie, voeg ik de records uit mijn array in, commit ik en begin ik een nieuwe transactie na het gebroken record.

Deze oplossing heeft me geholpen om de problemen te omzeilen die ik heb bij het behandelen van bestanden met slechte / dubbele records (ik had bijna 4% slechte records).

Het algoritme dat ik heb gemaakt, heeft me geholpen om mijn proces met 2 uur te verminderen. Laatste laadproces van bestand 1 uur 30 minuten dat nog steeds langzaam is, maar niet wordt vergeleken met de 4 uur die het aanvankelijk nam. Ik heb de inserts van 10.000 / s naar ~ 14.000 / s versneld

Als iemand nog andere ideeën heeft om het te versnellen, sta ik open voor suggesties.

BIJWERKEN:

Naast mijn antwoord hierboven, moet u er rekening mee houden dat invoegingen per seconde afhankelijk zijn van de harde schijf die u ook gebruikt. Ik heb het getest op 3 verschillende pc's met verschillende harde schijven en kreeg enorme verschillen in tijden. PC1 (1 uur 30 minuten), PC2 (6 uur) PC3 (14 uur), dus ik begon me af te vragen waarom dat zou zijn.

Na twee weken onderzoek en het controleren van meerdere bronnen: Hard Drive, Ram, Cache, kwam ik erachter dat sommige instellingen op je harde schijf de I / O-snelheid kunnen beïnvloeden. Door op eigenschappen op uw gewenste uitvoerstation te klikken, ziet u twee opties op het algemene tabblad. Opt1: Comprimeer dit station, Opt2: sta toe dat bestanden van dit station inhoud geïndexeerd worden.

Door deze twee opties uit te schakelen, nemen alle 3 pc's nu ongeveer dezelfde tijd om te eindigen (1 uur en 20 tot 40 minuten). Als u langzame invoegingen tegenkomt, controleer dan of uw harde schijf met deze opties is geconfigureerd. Het bespaart u veel tijd en hoofdpijn om de oplossing te vinden


11