Améliorations base de données/requêtes

Eléphanteau du PHP | 18 Messages

27 juin 2011, 15:18

Bonjour,

Je possède une base de données qui fait environs 215Mo, une table comporte 40 champs et contient 4600 données sachant que j'ai 72 tables donc 331 200 données.

Cette base contient des données météos et est réactualisé 4 fois par jours (toutes les 6h). Mon problème est que je met environs 72min pour réactualiser la base de données, en gros 1min par table pour réactualisé 4600 données.

Je voulais savoir si c'était normal est aussi si il y avait moyen d'amélioré la requête et la mise en base de données. En plus pendant la mise à jour la lecture des données est très très longue mais quand c'est mise à jour aucun problème pour afficher les données.

Cordialement. 8-)
http://www.meteo-gironde.net - Toute la météo en Aquitaine et par ville pour la France entière.

Eléphant du PHP | 80 Messages

27 juin 2011, 15:54

Waouw =D>
Et tu tiens vraiment à tout garder ? Tu ne veux pas scinder une partie pour la mettre en archive ?

Les tables sont bien structurés ? Pas de redondance ? Clé primaires partout ? Relations bien faites ? Bien réfléchi aux histoire 1,n - 1,n / 0,1 - 0,n / etc ?
En informatique, lorsqu'il y a un bug, le souci est toujours entre la chaise et le clavier.

Eléphant du PHP | 127 Messages

27 juin 2011, 17:28

Lors de l'import, privilégie les procédures stockées aux traitements PHP. En termes de performances c'est bien meilleur.
N'hésite pas à utiliser les transactions par faire des imports par lots de données.

Si tu as des indexes sur tes tables, vérifie qu'ils sont utiles et si non, supprime les. Les indexes augmentent la performance des requêtes en lecture mais coûtent en écriture/mise à jour.

Bon courage.

Eléphanteau du PHP | 18 Messages

27 juin 2011, 18:39

Merci pour vos réponses !

Donc les tables sont structurés comme ça :

Nom de la première table : data_01

Les champs :

ID | LONG | LAT | DATA1 | DATA2 | [...] | DATA40

Type de champ -> ID = mediumint(20)
Type de champ -> LONG/LAT = text
Type de champ -> DATA? = DOUBLE

Donc toute mes tables sont identiques et ça va jusqu'à la table "data_72"

Sachant que LONG et LAT ne changent jamais et se répètent sur toute les tables car les données ont comme référence LONG et LAT pour se mettre à jours.

Qu'entends-tu par 1,n - 1,n / 0,1 - 0,n /, Ez3kiel ?

Désolé mais c'est la partie (base de données) que je connais le moins donc toute les explications sont bonnes à prendre, car dans mon cas c'est la partie la plus importante.
http://www.meteo-gironde.net - Toute la météo en Aquitaine et par ville pour la France entière.

ViPHP
AB
ViPHP | 5818 Messages

28 juin 2011, 01:48

Et comment fais-tu ces mises à jour ? tu utilises des requêtes préparées ? Effectivement 1 mim pour 4600 lignes cela me semble beaucoup trop, il y aurait certainement moyen d'optimiser. T'a pas un bout de code pour montrer ton update ?

Eléphant du PHP | 209 Messages

28 juin 2011, 06:58

Il devrait y avoir moyen d'utiliser mysqlimport à partir d'un fichier texte que tu prépares avant.
--
Eric

Eléphant du PHP | 80 Messages

28 juin 2011, 09:01


Qu'entends-tu par 1,n - 1,n / 0,1 - 0,n /, Ez3kiel ?
Au vu de ta base, oublie, ce n'est pas important. :mrgreen:

Mais montre nous un peu le code qui fais les mises à jours et ajoute des enregistrements.
En informatique, lorsqu'il y a un bug, le souci est toujours entre la chaise et le clavier.

Eléphanteau du PHP | 18 Messages

28 juin 2011, 12:00

Alors je vous essayais de vous montrez mon script

Dans un premier temps j'ouvre tous mes fichiers txt de cette façon, donc j'ai 40 données donc 40 fois l'ouverture...

#-------------------------------------------------------------------CIN 0-180 mb-------------------------------------------------#

$fichier_CIN0180mb = "".$lien."CIN0180mb_".$varech.".txt"; // Nom de votre fichier

if($fp = fopen($fichier_CIN0180mb,"r")){ // Ouverture du fichier en lecture
$num = '0'; // Initialisation
while (!feof($fp)) { // Tant que non fin du fichier
$ligne_CIN0180mb[$num] = fgets($fp);
$num++; // Incrémentation
}
fclose($fp); // Fermeture du fichier
}
else
{ // Echec à l'ouverture
echo "Erreur : impossible d'ouvrir ".$fichier_CIN0180mb;
exit();
}

Ensuite je llui dis le nombre de ligne comme ceci :

$fin_ligne='4600';
$debut_ligne='1';

//Single DATA
$fin_CIN0180mb = $fin_ligne;
$num_ligne_CIN0180mb = $debut_ligne;

Et je fais une boucle qui va lire les lignes une par une (incrémentiel) de tous les fichiers txt (40 fichiers).

while ($num_ligne_CIN0180mb <= $fin_CIN0180mb &&
$num_ligne_DATA2 <= DATA2 &&
$num_ligne_DATA3 <= DATA3 &&
[...]
$num_ligne_DATA40<= DATA40)

{

$num_ligne_CIN0180mb++;
$num_ligne_DATA2++;
$num_ligne_DATA3++;
[...]
$num_ligne_DATA40++;


//Et après je fais un simple MYSQL UPDATE

mysql_query("UPDATE ".$table_data." SET
`CIN_0180mb`='$data_CIN0180mb[2]',
`DATA2`='$DATA2',
`DATA3`='$DATA3',
[...]
`DATA40`='$DATA40' WHERE `LAT`='$data_LAT' && `LONG`='$data_LONG'") or die(mysql_error());

}

Avec cette méthode toute mes données se mettent à jour en même temps pour les mêmes coordonnées.

Petite précisions quand même toute mes données se trouvent dans des fichiers séparés c'est à dire pour l'échéance +1h, j'ai un fichier txt pour la température, l'humidité, le vent...etc et celà jusqu'à +72h donc je traite 2880 fichiers txt (40*72).
http://www.meteo-gironde.net - Toute la météo en Aquitaine et par ville pour la France entière.

Eléphant du PHP | 127 Messages

28 juin 2011, 12:16

A ta place, je remplacerai ce code PHP en procédure stockée / traitement batch.

Un fichier SQL appelé grâce à un ksh, lui - même appelé par un crond (je suppose que c'est déjà le cas pour ton script PHP).

D'abord, chargement de tes fichiers TXT en tables temporaires (ou table de travail) avec des LOAD DATA INFILE.
Éventuellement, modifications sur tes données, traitements quelconques...
Enfin, copie des données correctement formatées vers tes tables de stockage.

A mon avis, ça ne devrait pas prendre plus de quelques secondes, quelques minutes grand max...

Eléphanteau du PHP | 18 Messages

28 juin 2011, 16:51

Bon j'ai commencé un script avec LOAD DATA LOCAL INFILE
$sqla = "LOAD DATA LOCAL INFILE 'TMP2m_01.txt' INTO TABLE `data_01` FIELDS TERMINATED BY ',' ENCLOSED BY '' LINES TERMINATED BY '\n' IGNORE 1 LINES ";

//$sqlb = "LOAD DATA LOCAL INFILE 'TMP500mb_01.txt' INTO TABLE `data_01` FIELDS TERMINATED BY ',' ENCLOSED BY '' LINES TERMINATED BY '\n' IGNORE 1 LINES ";
//$sqlc = "LOAD DATA LOCAL INFILE 'TMP850mb_01.txt' INTO TABLE `data_01` FIELDS TERMINATED BY ',' ENCLOSED BY '' LINES TERMINATED BY '\n' IGNORE 1 LINES ";

$resulta = mysql_query($sqla);
//$resultb = mysql_query($sqlb);
//$resultc = mysql_query($sqlc);
Mes données txt sont sous cette forme là

Code : Tout sélectionner

lon,lat,TMP 2 m above ground d=2011062806 1 hour fcst 358.058000,42.227000,292.889 358.124921,42.228272,293.967 358.191844,42.229503,296.262 358.258770,42.230694,296.388 358.325699,42.231845,296.551 [...]
Par contre mes tables ont cette structure là et je ne peux pas la changer car sinon faut que je crée une table en fonction de 1 données et de 1 échéance c'est à dire 2880 tables... so c'est pas possible :

ID | LONG | LAT | DATA1 | DATA2 | [...] | DATA40

Je sais pas si c'est bien de gardé le champ ID ou pas (dans mon exemple il y est pas)


Donc avec ce script ça marche très bien mais pour une seule donnée à la fois, comment faire pour mettre toute les données d'un coup dans la table sachant que les données sont toutes liés à LONG et LAT, en gros je voulais savoir si c'est possible de sélectionner le champ en fonction du fichier txt que je traite ?!

Avec cette requête c'est très rapide pratiquement instantané :shock:
http://www.meteo-gironde.net - Toute la météo en Aquitaine et par ville pour la France entière.

ViPHP
ViPHP | 3607 Messages

30 juin 2011, 09:10

Je reviens juste sur un point qui n'a pas été soulevé par les autres :
Type de champ -> LONG/LAT = text
là il y a clairement moyen d'optimiser, la moindre des choses c'est de remplacer text par varchar(10) (à toi de voir la taille de tes latitudes longitudes)
Ensuite tu peux envisager également des types tel que DECIMAL, FLOAT, REAL, et DOUBLE PRECISION ...
Il y en aura qui ne conviendrons pas puisque pas assez précis (Float par exemple), a voir ensuite qu'est-ce qui est le plus rapide? (tu peux faire des benchs)

Après réflexion, je ne sais pas si cette optimisation diminuera ton temps d'écriture, mais en tout cas la taille de la bdd oui :)
C'est déjà pas mal ;)

Eléphanteau du PHP | 18 Messages

04 juil. 2011, 12:08

$sqla = "LOAD DATA LOCAL INFILE 'TMP2m_01.txt' 
REPLACE INTO TABLE `data_01` 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '' 
LINES TERMINATED BY '\n' IGNORE 1 LINES (`LONG`, `LAT`, `TMP_2M`); ";

$sqlb = "LOAD DATA LOCAL INFILE 'TMP500mb_01.txt'
REPLACE INTO TABLE `data_01`
FIELDS TERMINATED BY ',' 
ENCLOSED BY '' 
LINES TERMINATED BY '\n' IGNORE 1 LINES (`LONG`, `LAT`, `TMP_500`); ";


$resulta = mysql_query($sqla);
$resultb = mysql_query($sqlb);
Admettons que j'ai une table avec ces champs là :

LONG | LAT | TMP_2M | TMP_500

Théoriquement avec cette requête tout les champs devraient se remplir et être les données écrasées si je recharge le fichier non ?

Car là ça me met tout à la suite mais seulement dans les champs LONG, LAT et TMP_2M et les données ne sont pas écrasées mais ajoutées, même avec le REPLACE..
http://www.meteo-gironde.net - Toute la météo en Aquitaine et par ville pour la France entière.