Performances de sed

Stephane Jourdois kwisatz-shell at rubis.org
Tue Sep 2 17:38:49 CEST 2008


On Mon, Sep 01, 2008 at 03:06:53AM +0200, Daniel Caillibaud wrote:
> Bonjour,
> 
> Je me suis écrit la petite fonction suivante (en bash) pour découper un dump mysql par tables (je rajoute ici des
> retours chariot pour la lisibilité).
> 
> split_sqldump() {
>   if [ $# -lt 1 ] ;
>   then 
>     echo "Il faut passer le fichier de sqldump en argument (et éventuellement un préfixe en 2nd arg)";
>   elif [ ! -f "$1" ] ; then echo "Le fichier '$1' n'existe pas"; 
>   else prefix="$2"; file="$1"; 
>     awk -F '`' '
>       BEGIN {l=0;lastl=1; tb=""; prefix="'"$prefix"'"; file="'"$file"'"}
>       {l=l+1}
>       /DROP TABLE IF EXISTS/ {
>         lasttb=tb; tb=$2;
>         if (lasttb != "") {
>           print "echo \"[`date '"'+%T'"'`] " lasttb " (" lastl "," l-1 ")\"";
>           print "sed -ne '"'"'" lastl "," l-1 " p; " l " q;'"'"' < \"'"$file"'\" > " prefix lasttb ".sql";
>         }
>         lastl=l;
>       }
>       END {
>         print "echo \"[`date '"'+%T'"'`] " tb " (" lastl ",fin)\"";
>         print "sed -ne '"'"'" lastl ",$ p;'"'"' < \"'"$file"'\" > " prefix tb ".sql";
>       }
>     ' < $file;
>   fi;
> };


Salut,

Je répond un peu à l'arrache parce que je n'ai pas le temps de te faire
une réponse complète mais voilà quelques idées :

1) première règle quand tu fais du parsage, tu t'arranges pour ne parser
qu'une seule fois (toi tu parses <nombre de tables>+1 fois, c'est ultra
dégueulasse, et évidemment les perfs s'en ressentent (sans parler de la
scalabilité en O(n) lors que tu pourrais faire du O(1)).

Le corollaire est la 2ème règle, qui est encore plus importante :

2) deuxième règle du parsage, tu parses en temps réel dès que c'est
possible, i.e. tu fais comme si tu parsais un stream, et tu fournis les
réponses asap.
Je m'explique :

- gcc prend un fichier, le parse, puis fait sa sauce. Il met tout le
  fichier en ram, puis commence à travailler, puis une fois qu'il a fini
il sort ce qu'il veut. Un peu comme tu as fait, sauf que toi tu as fait
un for (i=0; i < 100; i++) autour de l'appel :-)

- sort parse un stream, mais il ne commence à printer qu'une fois qu'il
  a tout le stream en ram. évidemment c'est mieux mais toujours pas top.

- cat, lui, il parse un stream et en plus il affiche au fûr et à mesure
  (modulo le cache éventuel sur stdout), c'est le must du parsage. En
général, les scripts sed/awk fonctionnent comme ça (par ligne, donc).


Donc pour finir, la bonne solution : tu écris un bête script (en sed,
awk, perl ou ce que tu veux) qui lit une ligne, réalise un traitement
sur cette ligne (en particulier un traitement dépendant de l'état, et un
traitement qui peut changer l'état), puis tu réitère jusqu'à la fin. Pas
de stockage nulle part, et un seul parsage.

Pour ton cas, et en perl, ça donne (écrit dans le mail donc non testé,
désolé :-)) :

-----
#!/usr/bin/perl
use strict;
use warnings;

my $db = undef; # Current database name
my $table = undef; # Current table name
my $fh = undef; # Current filehandle
while (<>) {
	if (/^CREATE DATABASE .* `([^`]+)`/) {
		$db = $1;
	} elsif (/^DROP TABLE IF EXISTS `([^`]+)`/) {
		$table = $1
		close $fh if $fh; # pas nécessaire vu que le open
				  # suivant ferme automatiquement
				  # le filehandle.
		open $fh, '>', "$db.$table.sql";
	}

	if ($db and $table) {
		print $fh $_ if $fh;
	}
}
close $fh;
-----

Je ne suis pas sûr que ça donne strictement le même résultat que ton
script vu sa complexité, mais bon ça me semble être un début pour toi.


Désolé encore une fois si j'ai loupé quelque chose dans ton mail, et
j'espère t'avoir aidé un peu. N'hésites pas à commenter.

++
Stéphane.

PS: Pour une réponse pure bash, c'est tout à fait faisable si tu la
veux, mais ce sera infiniment plus lent.

-- 
 ///  Stephane Jourdois     /"\  ASCII RIBBON CAMPAIGN \\\
(((    Consultant securite  \ /    AGAINST HTML MAIL    )))
 \\\   157 Bd Davout         X                         ///
  \\\  75020  Paris         / \    +33 6 8643 3085    ///


More information about the Shell mailing list