2009-09-21 10 views
0

Je crée une application web php qui permet à un utilisateur de télécharger une base de données MS Access (exportation csv) qui est ensuite traduite et migrée dans une base de données MySQL.Comment traduire et migrer des données

La base de données MS Access est constituée d'une table appelée t_product de 100k lignes. Cette table n'est pas bien conçue. À titre d'exemple, la requête suivante:

SELECT part_number, model_number FROM t_product 

retournera:

part_number model_number 
100 AX1000, AX1001, AX1002 
101 CZ10, CZ220, MB100 

Comme vous pouvez le voir, les numéros de modèle sont répertoriés sous forme de valeurs séparées par des virgules au lieu de dossiers individuels dans une autre table. Il y a beaucoup d'autres problèmes de cette nature. J'écris un script pour nettoyer ces données avant de les importer dans la base de données mysql. Le script mappera également les colonnes Access existantes à une base de données de conception relationnelle appropriée.

Mon problème est que mon script prend trop de temps à compléter. Voici son code simplifié pour expliquer ce que je fais:

$handle = fopen("MSAccess.csv, "r"); 

// get each row from the csv 
while ($data=fgetcsv($handle, 1000, ",")) 
{ 
mysql_query("INSERT INTO t_product (col1, col2 etc...) values ($data[0], $data[1], etc..."); 
$prodId = mysql_last_insert_id(); 

// using model as an example, there are other columns 
// with csv values that need to be broken up 
$arrModel = explode(',', $data[2]); 
foreach($arrModel as $modelNumber) 
mysql_query("INSERT INTO t_model (product_id, col1, col2 etc...) values ($prodId, $modelNumber[0], $modelNumber[1] etc..."); 
} 

Le problème ici est que chaque itération en boucle fait un très grand nombre d'appels à la base de données. Pour chaque enregistrement de produit, je dois insérer N numéros de modèle, Y numéros de pièce, X numéros de série etc ...

J'ai commencé une autre approche où j'ai stocké l'ensemble CSV dans un tableau. Je puis écrire une requête par lots comme

$sql = "INSERT INTO t_product (col1, col2, etc...) values "; 
foreach($arrParam as $val) 
$sql .= " ($val[0], $val[1], $val[2]), " 

Mais j'ai rencontré des erreurs de mémoire excessives avec cette approche. J'ai augmenté la limite de mémoire maximale à 64M et je manque toujours de mémoire.

Quelle est la meilleure façon de résoudre ce problème?

Peut-être devrais-je d'abord écrire toutes mes requêtes dans un fichier * .sql, puis importer le fichier * .sql dans la base de données mysql?

Répondre

0

J'ai décidé d'écrire toutes mes requêtes dans un fichier .SQL. Cela m'a donné l'occasion de normaliser le fichier CSV dans une base de données relationnelle appropriée. Ensuite, mon script php a appelé un exec ("mysql -h dbserver.com -u monutilisateur -pmypass nombbd < db.sql");

Cela a résolu mes problèmes de mémoire et il était beaucoup plus rapide que plusieurs requêtes de php.

1

Cela peut être pas entièrement la direction que vous voulez aller, mais vous pouvez générer le script de création MySQL directement à partir de MS Access avec le MySQL Migration Toolkit sans

Peut-être que vous pourriez permettre à l'utilisateur de télécharger le DB d'accès, puis votre script PHP appelle-t-il la boîte à outils Migration?

+0

La boîte à outils de migration optimisera également ses requêtes pour accélérer la traduction en bloc. –

0

Si vous essayez d'optimiser le code que vous avez déjà, j'essaierais d'agréger les INSERTS et de voir si cela aide. Cela devrait être facile à ajouter à votre code. Quelque chose comme ça (pseudocode C#):

int flushCount = 0; 

while (!done) 
{ 
    // Build next query, concatenate to last set of queries 

    if (++flushCount == 5) 
    { 
     // Flush queries to database 

     // Reset query string to empty 

     flushCount = 0; 
    } 
} 

// Flush remaining queries to the database