Ronny Seffner <[email protected]> hat am 1. August 2012 um 18:43 geschrieben:

> Hallo,
>
> ich habe regelmäßig (täglich) ein paar Daten aus einer proprietären Software
> anfallenden Textdateien in eine MySQL Datenbank zu packen. Als Admin kann
> ich mir mit BASH und MySQL ein wenig helfen, Programmierer bin ich damit
> nicht. Nun fällt erschreckend auf, wie langsam das Ganze ist und ich hoffe
> man kann mir hier helfen (im Zweifel dann auch bezahlt). Aber erstmal zu den
> Fakten:
>
> So sieht die Datei aus (es sind dann Dutzende dieser Dateien, mit je
> Tausenden Zeilen):
>
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:25        0,03296
> 03.05.2012 00:00:26        0,03296
> 03.05.2012 00:00:26        0,03296
> 03.05.2012 00:00:26        0,03296
> 03.05.2012 00:00:26        0,03296
> 03.05.2012 00:00:26        0,03296
> 03.05.2012 00:01:44        0,04413
> 03.05.2012 00:01:45        0,42134
> 03.05.2012 00:01:46        0,39369
> 03.05.2012 00:01:47        0,44423
> 03.05.2012 00:01:48        0,54073
> 03.05.2012 00:01:49        0,56819
> 03.05.2012 00:01:50        0,61855
> ...
>
> Sind mehrere Zeitstempel identisch, soll der _LETZTE_ Wert genommen werden.
>
> Das ist meine Tabelle:
>
> CREATE TABLE IF NOT EXISTS `test` (
>   `timestamp` datetime NOT NULL,
>   `value` decimal(10,5) NOT NULL,
>   PRIMARY KEY (`timestamp`)
> ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
>
> Ich vermute schon hier unüberlegt strukturiert zu haben. Ich möchte den
> Zeitstempel aber weiterverarbeitbar haben, da macht doch ein MySQL Format
> Sinn, auch wenn völliger Käse geliefert wird. Und weil ich ja nur den
> Letzten Eintrag bei identischen Zeitstempeln merken will, habe ich mich für
> "UPSERT" entschieden, also das Feld auf PRIMARY KEY gesetzt.
>
> Und hier nun mein primitives Skript, welches auf einer Core i3 3GHz Maschine
> mit 8gb RAM so 20 bis 30 Zeilen in der Sekunde ins MySQL schickt:
>
> cat "$FILE" | while read ENTRY; do
>   YEAR=`echo "$ENTRY" | awk '{print $1}' | awk -F. '{print $3}'`
>   MONTH=`echo "$ENTRY" | awk '{print $1}' | awk -F. '{print $2}'`
>   DAY=`echo "$ENTRY" | awk '{print $1}' | awk -F. '{print $1}'`
>   TIMESTAMP=`echo "$ENTRY" | awk '{print $2}'`
>   NEWDATE="$YEAR-$MONTH-$DAY $TIMESTAMP"
> #  VALUE=`echo "$ENTRY" | awk '{ print $3 }' | sed -e 's/,/./g'`
>   VALUE=`echo "$ENTRY" | awk '{ print $3 }'`
>   SQL="INSERT INTO \`test\` (\`timestamp\`, \`value\`) VALUES ('$NEWDATE',
> '$VALUE') ON DUPLICATE KEY UPDATE \`timestamp\`= '$NEWDATE', value =
> '$VALUE';"
>   mysql machines -uroot -p$SQLPWD -e "$SQL"
> done
>
> Ich denke hier jedes Mal mehrere awk und sed zu starten nur um das
> unglückliche Datumsformat zu verändern muss nicht sein. Leider kann ich kein
> perl, das soll ja Wunder wirken ...
>
> Aber auch ohne die Datumskonvertierung ist das alles nicht wirklich schnell.
> Die my.cnf ist noch UBUNTU Standard und vielleicht sind so viele kleine
> INSERTS auch gar nicht wirklich gut?

Viele Inserts (vor allem, wenn ein TX-basiertes System werkelt, und diese je in
einer einzelnen TX laufen) kosten halt Zeit.

Mein Ansatz wäre aber generell anders: erst mal in die DB, als ein Textfeld.
Demo mit PostgreSQL:

test=*# select * from ronny ;
                t
---------------------------------
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:25     0,03296
 03.05.2012 00:00:26     0,03296
 03.05.2012 00:00:26     0,03296
 03.05.2012 00:00:26     0,03296
 03.05.2012 00:00:26     0,03296
 03.05.2012 00:00:26     0,03296
 03.05.2012 00:01:44     0,04413
 03.05.2012 00:01:45     0,42134
 03.05.2012 00:01:46     0,39369
 03.05.2012 00:01:47     0,44423
 03.05.2012 00:01:48     0,54073
 03.05.2012 00:01:49     0,56819
 03.05.2012 00:01:50     0,61855
(18 rows)



Das einzulesen geht mit entsprechenden COPY-Befehl sehr flott.

Daraus kannst Du dann abfragen:


test=*# select distinct on (time) time, value from (select
to_timestamp(substring(t,1,20),'dd.mm.yyyy hh24:mi:ss') as time,
to_number(substring(t,22,50),'99D99999') as value from ronny) foo ;
          time          |  value
------------------------+---------
 2012-05-03 00:00:25+02 | 0.03296
 2012-05-03 00:00:26+02 | 0.03296
 2012-05-03 00:01:44+02 | 0.04413
 2012-05-03 00:01:45+02 | 0.42134
 2012-05-03 00:01:46+02 | 0.39369
 2012-05-03 00:01:47+02 | 0.44423
 2012-05-03 00:01:48+02 | 0.54073
 2012-05-03 00:01:49+02 | 0.56819
 2012-05-03 00:01:50+02 | 0.61855
(9 rows)

Noch eine Bemerkung zu Deinem _LETZTEN_ Datensatz: ohne ein ORDER BY gibt es in
Mengen, mit denen Datenbanken hantieren, kein Oben und kein Unten, kein Vorne
und kein Hinten. Das mußt Du genauer definieren.


Andreas




_______________________________________________
Lug-dd maillist  -  [email protected]
https://ssl.schlittermann.de/mailman/listinfo/lug-dd

Antwort per Email an