Inhalt:
- MySQL Dumps
- User anlegen
- Nützliches
- Platzbedarf von Datenbanken
- InnoDB Tablespace – Information
- Größe der innoDB-Logfiles berechnen
- Größe der innoDB-Logfiles sicher ändern
MySQL Dump
nur die Datenbank-Struktur sichern:
mysqldump -u root -p -d --all-databases > <filename>.sql |
Dump einer/mehrerer Datenbank(en):
mysqldump -u root -p --databases <database1> <database2> --result-file=<filename>.sql |
Dump aller Datenbanken:
mysqldump -u root -p --all-databases --result-file=<filename>.sql |
Dump bestimmter Tabellen:
mysqldump -u root -p <database> <table1> <table2> --result-file=<filename>.sql |
Dump einlesen:
mysql -u root -p < <filename>.sql |
Dump von bestimmten Spalten einer Tabelle:
Am Beispiel: Es soll eine Teil-Sicherung der Tabelle c_data gemacht werden. Es sollen nicht alle Spalten aus c_data, sondern nur ecu_gw, dbs_extern, dbs_extern_ip gesichert werden. Das lässt sich mit einem CONCAT-Statement realisieren. Es ist zu beachten, dass Mysql in das angegebene Verzeichnis für die Output-Datei schreiben darf. Dieses Quasi-Dump kann ganz normal eingespielt werden.
> mysql
use cmrblba_c
select concat(
"UPDATE c_data SET ecu_gw='"
,ecu_gw,
"', dbs_extern='"
,dbs_extern,
"', dbs_extern_ip='"
,dbs_extern_ip,
"' where dbname='"
,dbname,
"';"
) FROM c_data INTO OUTFILE
"/mnt/mysql/dump.sql"
;
Skript für Dump aller Datenbanken, aber es wird jede Datenbank in eine eigene Datei geschrieben mysqldump_each_single_file.sh:
#!/bin/bash # Dump mysql databases via mysqldump and write # each database in a single file # Exclude the following databases edb="information_schema performance_schema" # Use this prefix for backup file names prefix="$(date +'%Y-%m-%d')_$(hostname)_" # Use this suffix for backup file names suffix=".sql" # Compress backup files pack=$(which bzip2) dump=$(which mysqldump) if [ ! -x $dump ]; then echo "$dump not executable" exit 1 fi mysql=$(which mysql) if [ ! -x $mysql ]; then echo "$mysql not executable" exit 1 fi # Ask for password without prompt stty -echo read -p "Enter MySQL password for root: " pass; echo stty echo if [ "" = "$pass" ]; then echo "Login without password" dblogin='-u root' else dblogin="-u root -p$pass" fi ###################### # Execute backup # ###################### out="$($mysql $dblogin -Bse 'show databases')" # List for compressing files fc= # Loop over all databases for db in $out do # Don't skip any database as default skipdb=0 # If excludable databases are defined if [ "$edb" != "" ]; then # Loop over excludable databases for n in $edb; do if [ "$db" = "$n" ]; then skipdb=1 break; fi done fi if [ "$skipdb" = "1" ] ; then echo "Skip database $db" continue fi fn="./$prefix$db$suffix" echo "Dump database $db to $fn" $dump $dblogin --databases $db --result-file=$fn fc="$fc $fn" done ###################### # Compress backups # ###################### if [ $pack ] && [ -x $pack ] && [ "$fc" != "" ]; then echo "Compress $fc" $pack $fc fi
Skript mit Dialog-Oberfläche zum auswählen von Datenbanken für Dump in eine Datei mysqldump_select.sh:
#!/bin/bash # Dump selected mysql databases via mysqldump and write # the complete dump in a single file including master-data # Compress backup files #pack=$(which bzip2) pack='' # mysqldump binary dump=$(which mysqldump) if [ ! -x $dump ]; then echo "$dump not executable" exit 1 fi # mysql binary mysql=$(which mysql) if [ ! -x $mysql ]; then echo "$mysql not executable" exit 1 fi # file for temporary data data=$(mktemp /tmp/$(basename $0).XXXXXX) || exit 1 # trap it trap "rm -f $data" 0 1 2 5 15 # Read password and concatenate login string dialog --title "Mysql user root" --clear --insecure --passwordbox "Enter password" 10 30 2> $data pw=$(cat $data) if [ "" = "$pw" ]; then dblogin="-u root" else dblogin="-u root -p$pw" fi # Fetch databases alldbs="$($mysql $dblogin -Bse 'show databases')" # initialize database counter and checkbox options dbc=0 opt="" for db in $alldbs; do opt="$opt $db $dbc off" dbc=$(($dbc+1)) done # Define height more flexible height=$((5+$dbc)) if [ $height -gt 25 ]; then height=25 fi dialog --checklist "Choose databases for dump:" $height 40 30 $opt 2>$data mydb=$(cat "${data}") # Concatenate database string databases=""; for db in $mydb; do d=$(echo $db | sed -e "s/^.//" | sed -e "s/.$//") databases="$databases $d" done # Master data dialog --yesno "Write master informations (--master-data)" 0 0 if [ 1 = $? ]; then mopt='' else mopt="--master-data" fi dialog --inputbox "Enter dump file name" 0 0 2> $data fn=$(cat "${data}") $dump $mopt $dblogin --databases $databases --result-file=$fn dialog --msgbox "Done! Databases $databases has been saved." 0 0 dialog --clear
Skript zum Erstellen eines Dumps mit allen Usern und deren Passwörtern sowie Rechten mysql_user_dump.sh:
#!/bin/bash DBUSR="fb" DBPW="geheim" DB="mysql" ( mysql --batch --skip-column-names -h localhost -u "$DBUSR" --password="$DBPW" "$DB" -e "SELECT user, host FROM user" ) | while read user host do echo "# $user @ $host" mysql --batch --skip-column-names -h localhost -u "$DBUSR" --password="$DBPW" "$DB" -e "SHOW GRANTS FOR '$user'@'$host'" >> /home/fb/tools/mysql_user.sql done sed -i 's/.*/&\;/' /home/fb/tools/mysql_user.sql
User anlegen
create user
'user'
@
'host'
identified by
'password'
;
GRANT ALL PRIVILEGES ON *.* TO
'user'
@
'host'
IDENTIFIED BY
'password'
WITH GRANT OPTION;
Der Host ist auch eine Art Sicherheitsmaßnahme, denn der User hat nur Zugriff vom angegebenen Host. Host kann „localhost“, „%“ oder eine IP-Adresse sein. „%“ bedeutet Zugriff von überall her.
Nützliches
Überprüfen, welche Engine eine Tabelle benutzt. Alle Tabellen einer Datenbank:
SHOW TABLE STATUS FROM `database`; |
Eine spezielle Tabelle:
SHOW TABLE STATUS FROM `database` LIKE 'tablename' ; |
Doppelte Einträge in Tabelle finden (am Beispiel doppelter dbname in c_data):
select dbname, count(*) c from c_data group by dbname having c > 1 ; |
Skript zum Löschen aller Datenbanken (erstellt Drop-Statements):
Achtung! Vorsicht!
drop_all_db.sh
#!/bin/bash echo "***************************" echo "DANGER DANGER DANGER DANGER" echo "script drops all databases " echo "***************************" mysql -uroot -p -e "show databases" | grep -v Database | grep -v mysql| grep -v information_schema |gawk '{print "drop database " $1}' > drop.sql sed -i 's/.*/&\;/' drop.sql
Platzbedarf von Datenbanken
Platzbedarf aller Datenbanken:
SELECT concat( round( sum( data_length + index_length ) / ( 1024 * 1024 * 1024 \) , 2 ) , 'G' ) size FROM information_schema.TABLES ; |
Ausgabe Platzbedarf je Datenbank:
SELECT table_schema 'database' , concat( round( sum( data_length + index_length )/ ( 1024 * 1024 * 1024 ) , 2 ) , 'G' ) size FROM information_schema.TABLES GROUP BY table_schema ORDER BY sum( data_length + index_length ); |
Mit dieser Abfrage erhält man einen Überblick über den Speicherverbrauch pro Datenbank:
SELECT table_schema 'database' , concat( round( sum( data_length + index_length ) / ( 1024 * 1024 ) , 2 ) , 'M' ) size FROM information_schema.TABLES WHERE ENGINE= 'InnoDB' GROUP BY table_schema ORDER BY sum( data_length + index_length ); |
Mit dieser Abfrage erhält man einen Überblick über den Speicherverbrauch pro Tabelle einer bestimmten Datenbank (b2bbp):
SELECT table_name 'table' , concat(round((data_length+index_length)/( 1024 * 1024 ), 2 ), 'M' ) size FROM information_schema.TABLES WHERE ENGINE= 'InnoDB' AND table_schema = 'b2bbp' ORDER BY ( data_length + index_length ); |
InnoDB Tablespace – Information
– Durch (ungeordnetes) Schreiben und Löschen in die Datenbank kann es dazu kommen, dass der Tablespace mehr Speicherplatz im Filesystem nutzt als die Daten in der Datenbank eigentlich groß sind.
– Der Platz wird innerhalb des Tablesspaces wieder freigegeben, aber nicht im Filesystem. D.h. auf absehbare Zeit wird der Tablespace auch beim Hinzufügen von Daten erst einmal nicht weiter wachsen.
– Eine Möglichkeit bei InnoDB den Tablespace zu defragmentieren führt über Dump, Löschen und Import
– Es gibt die Möglichkeit Tabellen von vornherein in einen eigenen Tablespace pro Tabelle anzulegen
– Infos zur Realisierung: http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html
– Mit OPTIMIZE TABLE kann nicht verwendeten Speicher in der Tabelle freigeben und die Datendatei defragmentiert werden.
– Bei InnoDB wird OPTIMIZE TABLE auf ALTER TABLE umgesetzt, wodurch die Tabelle neu erstellt wird, um Indexstatistiken zu aktualisieren und ungenutzten Speicher im Cluster-Index freizugeben. Man muss beachten, dass MySQL die Tabelle während der Laufzeit von OPTIMIZE TABLE sperrt und eine hohe Auslastung verursachen kann.
Info über Löschen von großen Datenmengen in MySQL: http://mysql.rjweb.org/doc.php/deletebig
Größe der innoDB-Logfiles berechnen
Im Grunde muss die Größe der Logfiles groß genug sein, damit innoDB sein I/O optimieren kann, aber auch nicht zu groß, weil sonst ein Reparatur sehr lagne dauert. Aber wie soll diese Größe definiert werden? Es gibt eine gute Daumenregel.
Wir müssen uns auf dem MySQL-Server einloggen und die Logsequenz-Nummern mit einem Zeitabstand ausgeben lassen. Hier wähle ich eine viertel Stunde.
mysql> pager grep sequence PAGER set to 'grep sequence' mysql> show engine innodb status\G select sleep( 900 ); show engine innodb status\G Log sequence number 47 1246730202 1 row in set ( 0.01 sec) 1 row in set ( 15 min 0.13 sec) Log sequence number 47 1279159430 1 row in set ( 0.00 sec) |
Wir notieren uns die Logsequenz-Nummern. Das ist die Gesamtzahl von Bytes, welche in das Transaktionslog geschrieben werden. Wir können jetzt also berechnen wieviel Megabyte in einer viertel Stunde geschrieben wurden.
( 1279159430 – 1246730202 ) : 1024 :1024 = 30,9269 MB
Die Daumenregel besagt, dass man die Logs so groß machen kann, dass sie eine Stunde halten können. Das ist in der Regel völlig ausreichend. Hochgerechnet auf eine Stunde ergibt das:
30,9269 MB * 4 = 123,7076 MB
Diese Zahl wird noch aufgerundet auf das Dualsystem für eine gute Maßeinheit, also 128 MB. Weil es standardmäßig zwei Logfiles gibt wird die Zahl durch 2 geteilt und wir können 64 MB als Größe festlegen.
innodb_log_file_size=64M |
Quelle: http://www.mysqlperformanceblog.com/2008/11/21/how-to-calculate-a-good-innodb-log-file-size/
Größe der innoDB-Logfiles sicher ändern
Es ist nicht möglich die Größe einfach in der my.cnf zu ändern und dann den MySQL-Server neuzustarten.
Der MySQL-Server muss normal und sauber gestoppt werden. Dies kann mit dem Error-Log oder im Syslog überprüft werden. Wenn alles ok ist, werden die /var/lib/mysql/ib_logfile* nach /tmp/ verschoben, nicht löschen!
Jetzt kann der MySQL-Server wieder gestartet werden. Im Log sollten Meldung erscheinen wie:
May 27 16:59:06 bcdbs001 mysqld: 130527 16:59:06 InnoDB: Log file ./ib_logfile0 did not exist: new to be created
May 27 16:59:06 bcdbs001 mysqld: InnoDB: Setting log file ./ib_logfile0 size to 64 MB
May 27 16:59:06 bcdbs001 mysqld: InnoDB: Database physically writes the file full: wait…
May 27 16:59:07 bcdbs001 mysqld: 130527 16:59:07 InnoDB: Log file ./ib_logfile1 did not exist: new to be created
May 27 16:59:07 bcdbs001 mysqld: InnoDB: Setting log file ./ib_logfile1 size to 64 MB
May 27 16:59:07 bcdbs001 mysqld: InnoDB: Database physically writes the file full: wait…
May 27 16:59:09 bcdbs001 mysqld: InnoDB: The log sequence number in ibdata files does not match
May 27 16:59:09 bcdbs001 mysqld: InnoDB: the log sequence number in the ib_logfiles!
May 27 16:59:09 bcdbs001 mysqld: 130527 16:59:09 InnoDB: Database was not shut down normally!
May 27 16:59:09 bcdbs001 mysqld: InnoDB: Starting crash recovery.
May 27 16:59:09 bcdbs001 mysqld: InnoDB: Reading tablespace information from the .ibd files…
May 27 16:59:09 bcdbs001 mysqld: InnoDB: Restoring possible half-written data pages from the doublewrite
May 27 16:59:09 bcdbs001 mysqld: InnoDB: buffer…
May 27 16:59:10 bcdbs001 mysqld: 130527 16:59:10 InnoDB: Started; log sequence number 46 3591493132
An diesem Punkt kann man sagen, dass innoDB ordnungsgemäß funktioniert und die alten Logfiles unter /tmp/ können gelöscht werden.
Eine typische Fehlermeldung, dass innoDB bezüglich der Logfiles nicht startet, lautet:
ERROR 1033 (HY000): Incorrect information in file…
Ein Gedanke zu „MySQL – Know-how“