[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Bash Mysql Tutorial
[Thread Prev] | [Thread Next]
- Subject: Re: Bash Mysql Tutorial
- From: "Raphael H. Becker" <Raphael.Becker@xxxxxx>
- Date: Wed, 14 Dec 2005 11:15:17 +0100
- To: uugrn@xxxxxxxxxxxxxxx
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? > > Aeh, 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 fuer sich, deswegen empfiehlt es sich, alle Array-Operationen sequentiell abzuarbeiten, d.h. Zeile fuer Zeile. Richtg ist: * mysql nimmt SQL auf stdin entgegen * mysql erzeugt auf stdout eine tab-separierte Liste mit den Datensaetzen. 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 ueber 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 fuer den Zugriff] | # man mysql tail -n +2 | # Die Kopfzeile mit den Ueberschriften 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 # fuettern 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 fuer Zugriff] -------------------------------------------------- Oder stark verkuerzt: 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 ausfuehren, von der der select oben liest, dann kann es zu einer deadlock-Situation kommen, gerade wenn es sich um hunderte Datensaetze handelt. Alle Update-Befehle werden in eine Warteschlange gestellt und ausgefuehrt, 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 grosse 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 gewaehrleistet, dass die update-Statements erst dann ausgefuehrt werden, wenn der select zu Ende ist. Die tatsaechliche 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/ .........|.........|.........|.........|.........|.........|.........|..