Re: Bash Mysql Tutorial

Autor: Raphael H. Becker <Raphael.Becker_at_gmx.de>
Datum: 14.12.2005
On Sun, Dec 11, 2005 at 11:07:07PM +0100, Michael Lestinsky wrote:
> Am 11.12.2005 schrieb Christian Eichert:
> > Hat jemand ein Tutorial zum Thema Mysql und Bash?
> 
> Äh, wozu?
> 
>   echo "select * from Blubtable" | mysql -uuser -ppassword spinatdb

Das ist schon ein guter Anfang, aber man will ja meistens nicht nur
Daten aus einer DB rausholen, sondern auch damit sinnvoll arbyten. Und
dazu will ich kurz vorstellen, wie ich das in der Praxis handhabe:

Bash und Arrays sind so ein Thema für sich, deswegen empfiehlt es sich,
alle Array-Operationen sequentiell abzuarbeiten, d.h. Zeile für Zeile.

Richtg ist: 
        * mysql nimmt SQL auf stdin entgegen
        * mysql erzeugt auf stdout eine tab-separierte Liste mit den
          Datensätzen.


Das Kommando arbeitet nach dem EVA-Prinzip: Ein/Ausgaben auf
stdin/stdout, dazwischen der Zugriff auf die Datenbank, von dem das
drumherumliegende Shellscript nichts weiss. Vermutlich geht das auch mit
PGSQL oder auch anderen Datenbank-Shells auf Oracle, Informix, ... Das
script muss nichts über die darunterliegende Datenbank wissen, solange
das verwendete "Frontend" nur stdin/stdout bedient.

---> [mysql.stdin][mysql.db][mysql.stdout] -->
                    |   î
                    |   |
                    v   |
             [mysqld (Server)]




Will man damit sinnvoll arbyten, ist das ein guter Ansatz:

--------------------------------------------------

echo "select id,bla,fasel,blubber 
      from foo 
        [weitere joins]
      where bar=1
        [weitere Bedingungen]
      [weiteres SQL]
" | 
mysql [parameter für den Zugriff] |   # man mysql
tail -n +2 |                          # Die Kopfzeile mit den Überschriften wegwerfen
tr '\t' '|' |                         # alle Tabs durch "|" setzen, siehe IFS unten
while IFS='|' read ID BLA FASEL BLUBBER junk; do # Zeilenweise einlesen
  # in dieser Schleife kann mit den Werten $ID, $BLA, $FASEL und
  # $BLUBBER gearbytet werden, zB um damit irgendwelche befehle zu
  # füttern oder aber auch, um daraus wieder mit echo SQL auszugeben
  echo "update foo set xyz='abc mit $BLA und $FASEL', date=NOW(), blubber='${BLUBBER}__'  where id='$ID';"
done |
sort |          # Dieses sort ist nur unter bestimmten Bedingungen notwendig
mysql [parameter für Zugriff]

--------------------------------------------------

Oder stark verkürzt:

echo $SELECT | mysql | tail -n +2 | tr '\t' '|' | 
while IFS='|' read VARIABLEN junk; do [Arbyten mit VARIABLEN]; done


Warum das sort als vorletztes Element in der Pipe?

Wenn in der Schleife SQL-Statements erzeugt werden, die
Schreiboperationen auf der Tabelle ausführen, von der der select oben
liest, dann kann es zu einer deadlock-Situation kommen, gerade wenn es
sich um hunderte Datensätze handelt.

Alle Update-Befehle werden in eine Warteschlange gestellt und
ausgeführt, wenn der select beendet ist. Wenn zu viele update-Befehle
warten, dann nimmt der schreibende mysql-Prozess irgendwann keine Daten
mehr an und blockiert damit auch die Verarbytung der while-Schleife, die
wiederum u.U. den lesenden mysql-Prozess blockiert, der dann seinen
select nicht zu Ende bringen kann. In der Praxis habe ich so ein
Verhalten bisher nicht erlebt, weil die gesamte Pipe ziemlich elastisch
ist, d.h an vielen Stellen große Puffer beteiligt sind.

Der sort-Befehl bewirkt folgendes: er liest alle Daten aus stdin bis zum
Dateiende, d.h. solange, bis keine Daten mehr kommen, sortiert das ganze
dann um und gibt es auf stdout weiter. Damit ist als Seiteneffekt
gewährleistet, dass die update-Statements erst dann ausgeführt werden,
wenn der select zu Ende ist. Die tatsächliche Reihenfolge der
update-Statements ist idR egal.

Neuere Versionen von MySQL haben ein etwas kooperativeres Verhalten, 
was konkurrierende Zugriffe von select und update angeht. Sicher ist
sicher. 

Wenn der schreibende MySQL-Prozess in eine andere Tabelle schreibt als
die im join angegeben, kann man das auch parallel laufen lassen, und
damit potenziell auch schneller.

Das ganze Shellkonstrukt ansich ist ziemlich performant.

Weitere Beispiele:

Aus einem Vortrag:
  http://rabe.uugrn.org/scripts/vortrag/mysql.html

Stammtisch-Termine berechnen mit SQL-Ausgabe (insert-Statements):
  http://rabe.uugrn.org/scripts/uugrn_stammtischkalender.sh

FreeBSD Ports in MySQL abbilden:
  http://rabe.uugrn.org/scripts/FreeBSD/port-bla/import-urls.sh
  http://rabe.uugrn.org/scripts/FreeBSD/port-bla/load-descr.sh


Vielleicht solltest Du uns mitteilen, was genau Du Dir davon
versprichst, MySQL in Shellscripten zu verwenden, also welches Ziel du
damit verfolgst.

MfG
-- 
Raphael Becker                                    http://rabe.uugrn.org/
                      http://schnitzelmitkartoffelsalat.und.rahmspin.at/
.........|.........|.........|.........|.........|.........|.........|..


Received on Wed Dec 14 11:15:50 2005

Dieses Archiv wurde generiert von hypermail 2.1.8.
Zurück zur UUGRN-Homepage.