The Revenge of Mariadb IV

Es ist mal wieder Zeit für eine MariaDB Geschichte. Keine Panik, die wird nicht wieder biblisch werden 🙂

Es war mal wieder Zeit für ein OS-Upgrade

Mittlerweile waren drei OS-Releases ins Land gegangen und eine sich anbahnende Sicherheitslücke im Exim .. PSSST! Ich habe sie Euch nicht verraten. Tut so, also wenn Ihr nächste Woche das erste mal davon gelesen habt, ja? 😉 .. zwang zu einem schnellen Update auf eine nicht betroffene Version. Fedora 29 sollte es sein 😉

Nun, glücklicherweise war auch ein anderer Testserver noch auf der gleichen alten OS Release, so daß er als Testlauf herhalten durfte. Dieser Test lief ausgesprochen positiv ab, um genau zu sein, makellos. Daher wurde kürzestfristig entschieden, auch den eigentlichen Kandidaten auf die gleiche Art zu updaten. Ein Snapshot der VM und 30 Minuten später  war das Update komplett und der Server startete wieder.

Mailserver, Webserver, IMAP-Server, diverse Dienste liefen. Was natürlich nicht lief war die MariaDB .. Ätzzz. N I C H T  S C  H O N  W I E D E R!   Auch gutes Zureden, energisches Nachtreten mit systemctl änderte nichts an diesem Status, der Datenbankserver startete nicht.

Same procedure als last year, Miss Sophie?

Leider nein. Letztes mal hatte sich bekanntlich ein Konfigfile des Systemd geändert, so daß die zum Start nötigen Limits nicht gesetzt wurden. Natürlich wurde der DIFF Test vom letzten mal auch wieder angewendet, zeigte aber keinen Unterschied an. Also mußte die gute alte Methode „Start den Dienst von Hand, dann bekommst Du Infos“ herhalten.

Wie macht man das?

Wir schauen uns mal an, was der Systemd so starten wollen würde:

cat /usr/lib/systemd/system/mariadb.service

Da findet dann das hier:

ExecStartPre=/usr/libexec/mysql-prepare-db-dir %n
# MYSQLD_OPTS here is for users to set in /etc/systemd/system/mariadb@.service.d/MY_SPECIAL.conf
# Note: we set –basedir to prevent probes that might trigger SELinux alarms,
# per bug #547485
ExecStart=/usr/libexec/mysqld –basedir=/usr $MYSQLD_OPTS $_WSREP_NEW_CLUSTER
ExecStartPost=/usr/libexec/mysql-check-upgrade

Das POST können wir ignorieren, soweit kommen wir nicht, bleiben nur Pre und der eigentliche Dienststart.

Das in den einschlägigen Envfiles  unter /etc/sysconfig/ nichts steht, reicht also ein :

/usr/libexec/mysqld –basedir=/usr

für den Test aus. Ja super.. eine Fehlermeldung:   Can’t set requested open_files (1024) to 2000 …

Das lag an dem ulimit hier:

# ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 32088
max locked memory (kbytes, -l) 16384
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 32088
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Damit kann nicht mal die minimale Version der Datenbank starten 😉 Ergo geben wir ein: „ulimit -n 99999“ und starten es nochmal und siehe da, es hat sich doch wieder was geändert:

2019-06-04 23:13:41 0 [ERROR] /usr/libexec/mysqld: unknown variable ‚innodb_additional_mem_pool_size=50M‘
2019-06-04 23:13:41 0 [ERROR] Aborting

Wenn man denn endlich mal in Logfile schaut, sieht man dort auch die Warnung, daß sich das ja mal ändern könnte. Wer rechnet schon mit damit, daß da jemand mal Ernst macht 😉

2019-05-26 09:18:16 b753fd80 InnoDB: Warning: Using innodb_additional_mem_pool_size is DEPRECATED. This option may be removed in future releases, together with the option innodb_use_sys_malloc and with the InnoDB’s internal memory allocator.
2019-05-26 9:18:16 3075734912 [Note] InnoDB: innodb_empty_free_list_algorithm has been changed to legacy because of small buffer pool size. In order to use backoff, increase buffer pool at least up to 20MB.

Merke, erst ins Datenbank Log schauen, dann Server updaten!

Drei OS-Versionen sind dann vielleicht doch etwas happig bei einem Update. Diese Option findet man, so man sie gesetzt hat, in der Datei /etc/my.cnf . Anweisung auskommentieren, diesmal Datenbank über systemctl starten und läuft wieder 🙂

Und hier dachte ich eigentlich, ist die Story zu ende… war sie aber nicht!

Der an diesem Master angeschlossene Replications Elf ( Sklave sagt man im PCSG nicht mehr 😉 ) mochte die Replikationsblöcke vom Master nicht mehr lesen, weil Checksumme unbekannt! Das lag daran, daß der Replikations Elfe eine ältere Datenbankversion laufen hatte, da LTS. Einer langen Suche kurzes Ende:

Elfen anhalten: mysql -p -e „stop slave
auf den Master connecten: mysql -p -e „set global binlog_checksum=’NONE‘; SHOW MASTER STATUS;“ ausführen.

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000138 | 521505   |              |                  |
+------------------+----------+--------------+------------------+

Datenbank auf dem Master dumpen, auf den Elfen kopieren. Auf dem Elfen die Datenbank wipen, den SQL Dump einspielen.

Auf dem Elfen : mysql -p -e „change master to MASTER_LOG_FILE=’mysql-bin.000138′, MASTER_LOG_POS=521505;start slave

Sollte wieder gehen. Ging nicht.. Neuer Fehler! Statt:

Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'mysql-bin.000136' a'

gabs jetzt :

Last_IO_Errno: 1045
Last_IO_Error: error connecting to master 'test@masterserver:3306' - retry-time: 60  retries: 86400

Er zum Geier ist „TEST“ !?

Tja, keine Ahnung wie das passieren konnte, aber der „change master to …“ Befehl hatte den Replikationsusernamen durch „test“ ersetzt! Einfach so! Passwort war ok, Servername war ok, Username weg! Wie geil ist das denn ?!?!?

Also nochmal mit dem change master an den Elfen ran:

/usr/bin/mysql -p -e „stop slave;;CHANGE MASTER TO MASTER_USER=’myreplicationusername‘,MASTER_PASSWORD=’MeinPasswort‘;start slave

Da machste was mit als Admin … Ich wollte doch nur den Exim abdichten, nicht das Rad neu erfinden! Naja, jetzt gehts ja erstmal wieder 🙂 Und bevor noch einer fragt, nein, der Server hatte extern nur Port 25 zu bieten, deswegen ja auch das Update 😉

Linux – mysqldump sieht Leerzeichen als leeren Datenbanknamen an

Erinnert Ihr Euch noch an diesen Beitrag : Solution – mysqldump – No database selected when selecting the database aus dem Jahr 2016 ?

MariaDB & mysqldump

Damals stolperte ich über einen Fehler im Kommandozeilenparsing von Mysqldump.

Wie sich herausgestellt hat, konnte der Betreuer Michael Scholm bei Redhat die Ursache für das Problem entdecken. Kommt Ihr nie drauf: Das  war Schuld ! Oh ?! Ihr habt es nicht gesehen, hier nochmal  . Vielleicht mit der Lupe, da: > <. Ein Space.  Hier … zwischen dem „usr/bin/mysqldump“ und dem „–addlocks“ ist ein “ “ zuviel drin:

/usr/bin/mysqldump  --add-locks -e --force -R ....

Da es keine Option ist, wird es tatsächlich als valider Versuch, einen Datenbanknamen anzugeben gewertet.IMHO, ein Parser-Logik-Bug. Redhat sieht das anders: „not a bug“. Da jetzt raus ist, was es verursacht, kann man es ja leicht beheben.

etwas Kontext

Die Parser für Linux sind, sagen wir mal, ein bisschen eigen und deren Interpretation auch. Als Trenner zweier Argumente einer Kommandozeile gilt ein freistehendes Leerzeichen. Die Bash-Shell entfernt doppelte Leerzeichen und setzte ein Leerzeichen an die Stelle. So ein Leerzeichen zu viel ist schnell getippt und würde zu vielen „Dicke Finger-Syndrom“-Problemen führen, weil ..

… Ja, weil der Parser ohne diesen Trick, zwei Leerzeichen in Folge so übersetzen :

ls -la  foo => ls -la "" foo

Weil „Leerzeichen“ sind Trenner, also steht da oben eigentlich: „ls{Trenner}-la{Trenner}{Trenner}foo .

Wenn man aber zwischen den Trennern nichts hat, dann kommt ein leeres Argument raus. Was ein leeres Argument bedeutet, zeigt sich hier im Beispiel:

[marius ~]$ ls -la "" foo
ls: Zugriff auf '' nicht möglich: No such file or directory
ls: Zugriff auf 'foo' nicht möglich: No such file or directory

Wie man sehen kann versucht ls tatsächlich auf aka. „“ zuzugreifen. Wie das gehen soll ? Gar nicht. Ist ein Logikbug im Kontext von ls . Es wiederspricht der Natur eines ls , etwas aufzulisten, das es nicht gibt. Ergo müßte das Argument ignoriert werden. Jeder Mensch würde das so machen. Computerprogramme sind in der Beziehung blöde. Deswegen gibt es die Bash, die das Doppel-Leerzeichen wegnormaliziert und so vorhersehbare Fehler vermeidet, weil ..

Fehler vermeiden

wie man im obigen ls Beispiel gesehen hat, kann man es ja explizit angeben, wenn man muß => „“ oder “

MariaDB zieht sich jetzt auf den Standpunkt zurück, daß mysqldump sich ja nur wie ls verhalten würde. Tut es natürlich nicht, weil mysqldump komplett failed, wo ls einfach weitermacht und einen Fehler ausgibt.  Naja, Nobodys perfect.

Update

… oh, Redhat hat die Meinung geändert und einen Featurerequest bei MariaDB für einen besseren Parser erstellt. \o/ Das gibt einen dicken Daumen rauf! Mal sehen wies bei MariaDB ausgeht.

Wie man die TMP Ramdisk entfernt

Auf normalen Desktopsystemen ist es eine gute Sache, wenn der /tmp/ Ordner im RAM liegt. Auf /tmp/ wird sehr häufig und meistens eher kleinteilig zugegriffen, so das man diese Zugriffe  am besten von der Festplatte oder der SSD fern hält. Auf einem Server kann das aber auch von Nachteil sein.

[root@server ~]# df -h
Dateisystem    Größe Benutzt Verf. Verw% Eingehängt auf
devtmpfs        5,0G       0  5,0G    0% /dev
tmpfs           5,0G       0  5,0G    0% /dev/shm
tmpfs           5,0G    532K  5,0G    1% /run
tmpfs           5,0G       0  5,0G    0% /sys/fs/cgroup
/dev/xvda1      245G    178G   56G   77% /
tmpfs           5,0G     38M  5,0G    1% /tmp
tmpfs          1012M       0 1012M    0% /run/user/0

Im obigen Beispiel von einem unserer Server, kann man sehen, daß für die „tmpfs“ Laufwerke 5 GB maximale Größe angegeben ist. DEV, RUN, SYS werden das niemals erreichen, die sind eher im KB Bereich angesiedelt. Über die Sinnhaftigkeit, dann 5 GB als MAX Größe zu nehmen, kann man sicher streiten. Ist aber für die Betrachtung egal, denn es handelt sich um eine dynamische Speicherbelegung, deswegen auch „maximale Größe“. In Real sind die genau so groß, wie die Daten darin das brauchen. Lege ich dort 1 MB ab, ist es 1 MB und ein bisschen was für die Verwaltung groß.

An der „Verwendung“ in Prozent bzw. „Benutzt“ kann man auch sehen, das oben keins der TmpFS Ramdrives übermäßig belegt war. Die Ramdrives haben also bei dem Stand zusammen grade mal 39 MB echten Speicher belegt.

So weit, so gut.

Das obige Serversystem hat 10 GB Speicher zur Verfügung, was es üblicherweise auch braucht. d.h. es sind permanent mehrere GB an RAM in realer Benutzung.

Datenbankserver wie MariaDB erlauben es den Benutzern bei Abfragen sogenannte TEMP-Tables zu erstellen. Das wird vorzugsweise im RAM gemacht. Wenn aber das RAM nicht reicht, weil jemand einen TEMP-Table zusammen baut, der mehrere GB groß ist, dann wird das in den /tmp/ Ordner ausgelagert. Und man glaubt gar nicht wie unsensible mache Anwendungsentwickler im Umgang mit solchen Temp-Tables sind. „Killer SQL-Anweisungen“ in Shops, die „ein bisschen mehr und schneller“  gewachsen sind, als die Hersteller das erwartet haben, sind keine Seltenheit. Schlechtes Datenbankdesign sowieso nicht 😉  Und damit fängt der Ärger dann üblicherweise auch an.

Was bei einem Killer-SQL passieren kann …

Der Hauptspeicher des Datenbankserver hatte schon nicht ausgereicht um den Temp-Table anzulegen, und über die Ramdisk wird jetzt versucht den Speicher zusätzlich nochmal zu belegen, der vorher schon nicht ausreichend da war. Der Kernel wird jetzt versuchen diese Datenmengen zu swappen und kann das vielleicht nicht, weil die SWAP Partition zu klein ist. Nun kommt es zum „OOM“ dem Out-of-Memory-Error. d.h. der Kernel fängt an, scheinbar wahllos Prozesse zu killen, die viel Speicher belegen, aber noch nicht lange laufen. Eine genauere Analyse nimmt der Kernel leider nicht vor.

Wie kommt man jetzt aus der Falle wieder raus ?

Verantwortlich für das Erzeugen der Ramdisk ist diese Systemd Unit : /usr/lib/systemd/system/tmp.mount

#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Temporary Directory
Documentation=man:hier(7)
Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
ConditionPathIsSymbolicLink=!/tmp
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target

[Mount]
What=tmpfs
Where=/tmp
Type=tmpfs
Options=mode=1777,strictatime

Die kann man mit einem kurzen Befehl an den Systemd abschalten, allerdings erst ab dem nächsten Bootvorgang:

# systemctl mask tmp.mount
Created symlink from /etc/systemd/system/tmp.mount to /dev/null.
# ls -la /etc/systemd/system/tmp.mount
lrwxrwxrwx 1 root root 9 14. Nov 11:45 /etc/systemd/system/tmp.mount -> /dev/null

Danach muß man das also Rebooten. Am Ende ist /tmp/ dann wieder ein normaler Ordner auf der Festplatte, der keiner Größenbeschränkung unterliegt und in dem der Datenbankserver dann auch wieder fast beliebig große Temp-Tables erzeugen kann, ohne das gleich ein unschuldiger Prozess dran glauben muß.

 

Wie man PHPMyAdmin beschleunigen kann

Habt Ihr auch einen „modernen“ PHPMyAdmin installiert, der bei einigen Anzeigen gefühlte Äonen braucht, um den banalen Inhalt der Datenbank anzuzeigen ?

Ja ? Habt Ihr auch schon gedacht, daß es an der DNS Auflösung liegen könnte ?
Ja ? und es hat so gar nichts gebracht ein schnelleres Cache  einzustellen ?
Ja ? Na dann schaltet doch mal auf ENGLISCH als PMA Sprache um, Ihr werdet Euch wundern !

Es ist einen :facepalm: wert, denn für jede popplige Seite, sei es per AJAX oder per URL Link, lädt PHP die komplette, wirklich MB große Übersetzung, wenn man Deutsch eingestellt hat. Da hilft auch kein Filecache mehr um das zu beschleunigen!

Wie man sowas findet

Sehen tut man das erst, wenn man mit STRACE den Apachen und die ausgeführten PHP Programme traced.

strace -e open,read -f -p `pidof httpd | sed -e "s/ /,/g"`

Es folgt so etwas, in einer schieren Unzahl von Zugriffen, weil PHP echt groß ist und ne Menge einlesen muß.

[pid 10052] open(„/usr/lib/php/modules/intl.so“, O_RDONLY|O_CLOEXEC) = 3
[pid 10052] read(3, „…………………………….jede Menge Text ………………“, 512) = 512

Das oben ist keiner der verdächtigen Zugriffe, zeigt aber, wie man die READs den Dateien zuordnet. Das Orangerote ist der FILEDESCRIPTOR, kurz FD.  Jede Datei die man öffnet als Programm, bekommt einen eindeutigen FD, damit man das als Programm zuordnen kann.

Typisch für PHP und die Übersetzungen sind diese Zeilen :

[pid  9436] lseek(4, 93205, SEEK_SET)   = 93205
[pid  9436] lseek(4, 93205, SEEK_SET)   = 93205
[pid  9436] read(4, „Database %s has been dropped.\0Database Log\0Database client version:\0Database comment\0Database for user account\0Database level tabs\0Database name\0Database name template\0Database operations\0Database seems to be empty!\0Database server\0Database structure\0Database system or older MySQL server to maximize output compatibility with:\0Database tree separator\0Database used for relations, bookmarks, and PDF features. See [a@http://wiki.phpmyadmin.net/pma/pmadb]pmadb[/a] for complete information. Leave blank for no support. Suggested: [kbd]phpmyadmin[/kbd].\0Database-level tabs\0Database-specific privileges\0Database:\0Databases\0Databases display options.\0Databases statistics\0Databases:\0Date\0Deactivate now\0Deactivate tracking for %s\0Debug SQL\0Dec\0December\0Default\0Default database tab\0Default format; be aware that this list depends on location (database, table) and only SQL is always available.\0Default language\0Default server\0Default server tab\0Default sort order for tables with a primary key.\0Default sorting order\0Default ta“…, 8192) = 8192

Warum PHP 8KB Blöcke einliest, statt min. 64KB wird ewig ein Geheimnis bleiben, scheint aber ein Relikt aus den Anfängen zu sein 🙂

Es gilt, wenn der einzulesende Datenblock, der Blockgröße auf im Filesystem entspricht, dann kann das OS den Datenstrom am effizientesten einlesen. Der Datenzugriff sollte nicht größer als die Blockgröße sein, wobei ganze Mehrfache der Blockgröße ok wären. Wenn jetzt wie bei PHP 8KB eingelesen werden, die Datenblockgröße aber 64 KB ist, braucht das OS schon 8x soviele Filezugriffe nebst Performanceoverhead durch die Lesefunktionen, um den gleichen Inhalt eines Blockes einzulesen. Dazu muß die Platte den Kopf 8x zu dem Datenblock fahren, falls auf einem System noch mehr los ist, als nur dieses einzige Programm. Was man getrost annehmen kann.

Sowas ist einfach ineffizient. Ganz besonders ineffizient, wenn die Datei, die man da einlesen will, mehrere MB groß ist.

Ich hoffe, es hilft Euch ein bisschen bei Euren eigenen Problemen.

 

 

SQLITE Disk IO Error

Manchmal ist es zum Mäuse melken und der Fehler „General error: 10 disk I/O error“ vom SQLLite PDO Teiber von PHP gehört dazu:

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 10 disk I/O error'

Wenn Sie das bekommen, schauen Sie doch mal nach, ob Ihr User auch genug Speicherplatz zur Verfügung hat und die Daten zu schreiben. Lassen Sie sich nicht davon täuschen, daß Sie als Root User in der Shell direkt mit dem SQLLite Befehl in der Datenbank sauber schalten und walten können 😉

Genug RAM gibt es gar nicht…

“ ‚Auf der Suche nach der Wahrheit, muß der Adept allerlei Prüfungen des Geistes und Körpers über sich ergehen lassen.‘ „Prüfungen kann ich ertragen, Meister, aber an Langweile werde ich sterben.“ “ ( aus den Büchern Groths )

So geht es mir auch grade 🙂 Ich bin auf der Suche nach der Wahrheit hinter einem DNS Fehler, aber diese Wahrheit bedeutet Stress pur. Bosten läuft zum dritten Marathon durch, und kein Ergebnis, dafür aber Heldenleistungen bei den Prozesswerten.

Dabei fing alles mit einer harmlosen Frage an :

Bluefish3

Sehr lang ist noch milde ausgerückt, denn SQL Dumps werden von MySQLdumper dummerweise so gemacht, daß sie riesige Anweisungsketten sind, die mit einem einzigen INSERT mal ebend hunderttausende bis Millionen von Tabellenzeilen schreiben. Der MysqlServer schafft das deutlich besser als BlueFish 🙂

Wie man hier schön sehen kann, sollte ein Texteditor so nicht in der Prozessliste aussehen:

3.7 GByte RAM verbrauch für ein 2 GB SQL File

3.7 GByte RAM verbrauch für ein 2 GB SQL File

Und seit ca. 20 Minuten sieht man das Bild :

Bluefish2
Keine Ahnung was am Laden von 2 GB Text so viel CPU ziehen kann 😉  Sehr positiv, der Rest vom System reagiert noch richtig gut 🙂 Wozu hat man auch 8 Kerne ? Die langweilen sich ja sonst eh den ganzen Tag.

Nach 30 Minuten glaube ich langsam daran, daß sich …. nein… jetzt, fertig? Dramatik bei BlueFish.. RAM Verbrauch droppt von 3.7 GB auf 1.9 GB , aber dafür mußte etwas ausgelagert werden.. Gnome ist jetzt leider der Meinung, daß BlueFish nicht mehr auf Eingaben reagiert ( stimmt ), und möchte es terminieren, aber Bluefish ackert noch 😉  … Eine Geduldsprobe sonders gleichen..  Das Bluefish verloren hat, weil mir der Geduldsfaden geplatzt ist 🙂

Alternativen sind gefragt !

Die Anwendungen im Desktop sind alles Luschen, da müssen die Kollegen von der Bash ran 🙂

3 Minuten zum Entpacken des SQL Dumps von BZIP2 in Rohtext.
1 Sekunde zum Prüfen mit head, daß kein use database; im Dump steht.
10 Sekunden um zu sehen, daß der SQL beim Einsortieren die gesuchte Tabelle bereits eingefügt hat
10 weitere Sekunden um einen Select laufen zu lassen, der die gesuchten Informationen ausgibt.

In your Face DESKTOP ! 😀

Und das alles nur, weil der (sich beschwerende ) Kunde, seinen SOA Eintrag selbst gelöscht hat.

Was lernen wir daraus ?

  1. Ein Boston mp3 alleine macht noch keine gute Musikschleife
  2. Überbewerte Deinen Texteditor nicht, er ist nur für typische Desktopanwendungsfälle gemacht
  3. Bash rulz!

 

Solution – mysqldump – No database selected when selecting the database

International shortform:

Hi, if you reached this page, because it’s one of five webpages regarding this specific error message, please scroll down to the end.

Und für alle anderen, die lange Form:

Die Shell kann komisch sein, aber die Abwesenheit der Bashshell ist noch zu viel komischeren Sachen fähig, eine davon ist der Bug von Mysqldump keine Datenbank angegeben zu haben.

Hintergrund: Wenn man in Java mit Exec() einen Befehl startet, hat man keine Shell vor sich und damit auch eine Menge Sicherheitsprobleme nicht mehr. Nachteil : u.a. „*“ wird nicht mehr funktionieren, denn das wird von der Bash geparst. Keine Bash => Kein „*“ Keine „<>“ .

Das kennt man noch. Was jetzt kommt, ist allerdings extrem schwer zu debuggen, deswegen bin ich auch ein klein bisschen stolz als einziger im Netz eine Lösung präsentieren zu können, auch wenn die eher trivialer Natur ist. Sucht mal nach der Fehlermeldung, es gibt nur 4 Seiten, die diese Meldung behandeln 😉 (OK, jetzt 5 )

Das hier ist der Befehl:

/usr/bin/mysqldump  --add-locks -e --force -R --triggers --add-drop-table --hex-blob -h localhost --password=dbpass --user=dbuser dbname;

Das erzeugt die Fehlermeldung :

mysqldump: Got error: 1046: No database selected when selecting the database

obwohl eine Datenbank angegeben ist. Gibt man den  Befehl in die Shell ein, geht es sofort ohne Anpassungen. Kleine Anmerkung, auf die Fehlermeldung an sich muß man geistig erstmal kommen, richtig wäre nämlich „no databasename given“

Wie löst man das jetzt, wenn man doch schon alles richtig angegeben hat ?

Na man drückt dem Befehl die Pistole auf die Brust, so daß er sich nicht mehr herausreden kann ;D

/usr/bin/mysqldump  --add-locks -e --force -R --triggers --add-drop-table --hex-blob -h localhost --password=dbpass --user=dbuser --databases dbname

Der kleine Zusatz „–databases“ ist eigentlich dazu da, mehr als eine Datenbank in einen SQL-Dump zu integrieren. Es geht aber auch nur mit einer einzigen Datenbank und komischerweise kommt der Parser jetzt nicht mehr durch einander und erkennt die Datenbank am Ende des Befehls. Es gibt so bescheuerte Bugs 😀

Ok, Hello there.  You found this page, because it’s the only one marked as solution to the problem, that you give mysqldump a databasename and it says, that you did not. It’s a bug that occurs only in the absence of bash. You counter it by adding „–databases “ infront of your databasename. See the above example if your uncertain how to do it.

If you wanne see more articles in english, please leave a comment about it. Cu.

 

2038 ist schneller da als man denkt

In 23 Jahren, wenn die Unixwelt Y2K erlebt, wird die Welt zusammenbrechen.

Wir haben ja jetzt 2015 und die gängigste Datenbank MySQL legt Timestampfelder immer noch als 32-Bit Feld an. Es sollte ja eigentlich kein Problem sein dort intern 64-Bit zu benutzen, aber wie das so ist, die Tücke liegt im Detail.

MySQL speichert die Daten in einer großen Datei im Binärformat. In dem Augenblick wo dieser Feldtype auf 64-Bit umgestellt wird, muß zwangsweise mysql_upgrade laufen, sonst gibt es nur Probleme. Und wie das Leben so spielt,  mysql_upgrade wird bei normalen Updates eigentlich nie ausgeführt. Da muß man als Admin selbst machen.

„Wenn das noch 23 Jahre sind, warum nervst Du jetzt schon rum?“

Ich kenne Euch halt 🙂 Dabei wollte ich auf etwas anderes hinaus:

Führt öfter mal mysql_upgrade durch. Erst dieser Befehl schreibt die Strukturen im Mysql um z.b. wenn neue Felder in der „mysql“ Datenbank hinzugekommen sind. Mit den Updates von Fedora 20 auf 21 z.b. mußte so ein mysql_upgrade auch zwangsweise laufen, wenn man die neuen „Features“ benutzen wollte.

Zurück zum Jahr 2038. Es werden dann mehr als 40 Jahre zwischen den Leuten liegen, die Y2K mitgeplant haben und denen, die dann für die Systeme verantwortlich sind. Da darf man annehmen, daß die meisten das auf die gleiche leichte Schulter nehmen werden, wie Ihre Vorfahren.

Deswegen wünsche ich heute schon einen schönen Weltuntergang 😉

Tip: Update der Inhalte eines SQL Views

In einer Datenbank wie MySQL kann man sich Selects als Pseudotabellen anlegen und dann selbst wieder über den diese Tabelle einen Select bauen. So etwas nennt man einen View.

Beispiel:

SELECT a.vorname,a.name,b.beruf as beruf FROM Personen as a,Berufe as b WHERE a.berufsid=b.id;

Wenn man diesen Select als View anlegt, hat man drei Felder : Vorname,Name,Beruf

Nennen wir den View mal Test, wäre dieser Select möglich :

SELECT vorname,name FROM Test WHERE beruf = „Bäcker“;

Wenn man nun versucht den VIEW mit UPDATE zu ändern, geht das eigentlich nicht, weil es eine nicht eindeutige Beziehung der Datensätze untereinander ist.

Für mein aktuelles Pandora Projekt habe ich nun einen View gebaut, bei dem das Update tatsächlich möglich ist:

select `pa`.`id` AS `id`,`pa`.`vorname` AS `vorname`,`pa`.`nachname` AS `nachname`,`pa`.`server` AS `server`,`pc`.`value` AS `friendmode` from (`pandora`.`pandora_config` `pc` join `pandora`.`pandora_account` `pa`) where ((`pa`.`id` = `pc`.`uid`) and (`pc`.`name` = ‚michsuchen‘))

Das funktioniert aufgrund dieser Beziehung „((`pa`.`id` = `pc`.`uid`)“ , denn in beiden Tabellen gibt es exakt einen eindeutigen Datensatz. d.b. :

Für jede Person gibt es exakt einen Config Eintrag in der anderen Tabelle. Damit kann der Datenbankserver jetzt die logische Verbindung der Datensätze „rückwärts“ auflösen und in der richtigen Tabelle den richtigen Eintrag ändern:

UPDATE `pandora_userliste` SET friendmode = ‚erlauben‘ WHERE vorname =’meinvorname‘;

Damit ist der View Read/Writeable geworden was es man mit Hilfe des ORDB Frameworks ausnutzen kann, denn Views werden ein Java Datenobjekte erzeugt. Über Views lassen sich schlanke Strukturen und Datenbankobjekte erzeugen, die dazu noch updatefähig sein können (aber nicht müssen). Als Folge davon erhält man übersichtliche Datenbankstrukturen, die von einem Menschen leicht gelesen und verstanden werden können, aber trotzdem Datenbanktechnisch höchst performant gestaltet sein können.

Error 2006: Server has gone away

Diese falsche Fehlermeldung eines MySQL Servers, verleitet einen unweigerlich dazu an einen echten Fehler des Servers zu denken. Glücklicherweise kann es auch andere Fehlergründe geben. Einen davon, zeigen wir Ihnen heute:

Wenn Sie einen SQL DUMP importieren, der 2,4 MB groß ist, aber sqlmäßig nur aus einer Zeile des Schemas:

insert into datentabelle ( spalte1,spalte2,spalte3) values (1,2,3),(2,3,4) ,(3,4,5) ,(4,5,6) ,(2384,4233,5674),..... 2 MB später ... ;

besteht, müssen Sie sich nicht wundern, wenn es nicht geht. Die Zeile ist schlicht intern zu lang.

Abhilfe schafft der MySQL eigene Befehl replace :

 replace ")," ");insert into datentabelle  ( spalte1, spalte2, spalte3 ) values " --  /tmp/output-1.sql

Wenn Sie diesen neuen SQL Dump einspielen, wird dies anstandslos verarbeitet werden.