partitionierte_tabellen_mit_mysql
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
| partitionierte_tabellen_mit_mysql [2019-05-02 14:59:09] – manfred | partitionierte_tabellen_mit_mysql [2024-03-28 14:07:29] (aktuell) – [PARTITION BY HASH] manfred | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| + | ====== partitionierte Tabellen mit MySQL ====== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * **[[https:// | ||
| + | |||
| + | __Der Spaltentyp " | ||
| + | |||
| + | MySQL 5.7: welche Tabellen sind in dieser DB partitioniert? | ||
| + | SELECT TABLE_SCHEMA, | ||
| + | |||
| + | wievile Einträge sind in einer bestimmten Partition? | ||
| + | SELECT count(*) AS ' | ||
| + | |||
| + | |||
| + | ===== Partitionstypen in MySQL ===== | ||
| + | |||
| + | Diese Partitionstypen gibt es bei MySQL: | ||
| + | * [[http:// | ||
| + | * [[https:// | ||
| + | |||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | |||
| + | |||
| + | ===== eine vorhandene Tabelle partitionieren ===== | ||
| + | |||
| + | |||
| + | ==== PARTITION BY RANGE ==== | ||
| + | |||
| + | Ggf. ist es nötig, bevor man eine vorhandene Tabelle partitionieren kann, den Typ der einiger Spalten anzupassen und oft muss auch der '' | ||
| + | |||
| + | zum Beispiel einen '' | ||
| + | ALTER TABLE `datenbank`.`tabelle` | ||
| + | CHANGE COLUMN `id` `id` bigint(20) NOT NULL AUTO_INCREMENT, | ||
| + | CHANGE COLUMN `time` `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ' | ||
| + | ; | ||
| + | |||
| + | ALTER TABLE `datenbank`.`tabelle` | ||
| + | DROP PRIMARY KEY, | ||
| + | ADD PRIMARY KEY (`id`, | ||
| + | ; | ||
| + | |||
| + | ALTER TABLE `datenbank`.`tabelle` | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(time)) ( | ||
| + | PARTITION p201904 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201905 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201906 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201907 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201908 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201909 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201910 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ) | ||
| + | ; | ||
| + | |||
| + | <code bash> | ||
| + | #!/bin/bash | ||
| + | |||
| + | SICHERE_TAGE=" | ||
| + | |||
| + | DATENBANK=" | ||
| + | TABELLE=" | ||
| + | MYSQL=" | ||
| + | |||
| + | |||
| + | # für jeden Tag eine Partition anlegen | ||
| + | echo " | ||
| + | ALTER TABLE ${DATENBANK}.${TABELLE} | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(datetime)) ( | ||
| + | $(for i in $(seq -7 ${SICHERE_TAGE}) | ||
| + | do | ||
| + | echo " | ||
| + | done | tac) | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ) | ||
| + | ; | ||
| + | " | ${MYSQL} | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== PARTITION BY HASH ==== | ||
| + | |||
| + | * [[https:// | ||
| + | |||
| + | Um eine Tabelle nach HASH zu partitionieren, | ||
| + | |||
| + | // | ||
| + | |||
| + | Man sollte die Anzahl der Partitionen als einen Wert von '' | ||
| + | <file SQL Tabelle_partitionieren_-_HASH.sql> | ||
| + | ALTER TABLE `promotion_tracking_backend`.`CrossSiteTrackingData` | ||
| + | PARTITION BY HASH (id) | ||
| + | PARTITIONS 16; | ||
| + | </ | ||
| + | |||
| + | SELECT TABLE_SCHEMA, | ||
| + | |||
| + | |||
| + | ==== PARTITION BY LINEAR HASH ==== | ||
| + | |||
| + | * [[https:// | ||
| + | |||
| + | **LINEAR HASH Partitioning: | ||
| + | MySQL unterstützt auch lineares Hashing, das sich von regulärem Hashing darin unterscheidet, | ||
| + | |||
| + | //'' | ||
| + | |||
| + | <code sql> | ||
| + | ALTER TABLE `promotion_tracking_backend`.`CrossSiteTrackingData` | ||
| + | PARTITION BY LINEAR HASH (id) | ||
| + | PARTITIONS 16; | ||
| + | </ | ||
| + | |||
| + | ===== partitionierte Tabelle neu anlegen ===== | ||
| + | |||
| + | Es ist wichtig, dass alle Spalten, die in der '' | ||
| + | |||
| + | <file SQL partitionierte_Tabelle.sql> | ||
| + | DROP TABLE log_db.log; | ||
| + | CREATE TABLE log_db.log ( | ||
| + | id int(11) NOT NULL AUTO_INCREMENT, | ||
| + | category varchar(255) DEFAULT NULL, | ||
| + | level int(11) DEFAULT NULL, | ||
| + | SERVER_PROTOCOL varchar(250) DEFAULT NULL, | ||
| + | REQUEST_METHOD varchar(250) DEFAULT NULL, | ||
| + | REQUEST_TIME double DEFAULT NULL, | ||
| + | QUERY_STRING varchar(250) DEFAULT NULL, | ||
| + | HTTP_ACCEPT_ENCODING varchar(250) DEFAULT NULL, | ||
| + | HTTP_CONNECTION varchar(250) DEFAULT NULL, | ||
| + | HTTP_HOST varchar(250) DEFAULT NULL, | ||
| + | HTTP_REFERER varchar(250) DEFAULT NULL, | ||
| + | HTTP_USER_AGENT varchar(250) DEFAULT NULL, | ||
| + | HTTPS varchar(250) DEFAULT NULL, | ||
| + | REMOTE_ADDR varchar(32) DEFAULT NULL, | ||
| + | REMOTE_PORT smallint(6) DEFAULT NULL, | ||
| + | SCRIPT_FILENAME varchar(250) DEFAULT NULL, | ||
| + | REQUEST_URI varchar(250) DEFAULT NULL, | ||
| + | sessionid varchar(32) DEFAULT NULL, | ||
| + | session_data text, | ||
| + | post_data text, | ||
| + | user varchar(64) DEFAULT NULL, | ||
| + | message text, | ||
| + | zeitpunkt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| + | PRIMARY KEY (id, | ||
| + | KEY user (user) | ||
| + | ) | ||
| + | |||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(zeitpunkt)) ( | ||
| + | PARTITION p201806 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201807 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201808 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | ) | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | > echo " | ||
| + | |||
| + | Jeder Monat wird in eine eigene Partition geschrieben. | ||
| + | |||
| + | > ls -lha / | ||
| + | total 268K | ||
| + | drwxr-x--- 2 mysql mysql 4,0K Mai 23 16:10 . | ||
| + | drwxr-xr-x 9 mysql mysql 4,0K Mai 23 11:44 .. | ||
| + | -rw-r----- 1 mysql mysql 65 Mai 16 17:51 db.opt | ||
| + | -rw-r----- 1 mysql mysql 14K Mai 23 16:29 log.frm | ||
| + | -rw-r----- 1 mysql mysql 112K Mai 23 16:29 log# | ||
| + | -rw-r----- 1 mysql mysql 112K Mai 23 16:29 log# | ||
| + | -rw-r----- 1 mysql mysql 112K Mai 23 16:29 log# | ||
| + | |||
| + | |||
| + | ===== Partitionen zu einer Tabelle hinzufügen bzw. entfernen ===== | ||
| + | |||
| + | [[https:// | ||
| + | ADD- oder DROP-Operationen für RANGE- oder LIST-Partitionen sind sofortige Operationen oder fast sofortige. | ||
| + | ADD- oder COALESCE-Operationen für HASH- oder KEY-Partitionen kopieren Daten zwischen allen Partitionen, | ||
| + | Dies entspricht im Grunde genommen dem Erstellen einer neuen Tabelle, obwohl die Operation ADD oder COALESCE Partition für Partition ausgeführt wird. | ||
| + | REORGANIZE-Operationen kopieren nur geänderte Partitionen und berühren keine unveränderten Partitionen. | ||
| + | |||
| + | <file SQL neue_partition_zur_Tabelle_dazu.sql> | ||
| + | # | ||
| + | # Neue Partition anlegen. | ||
| + | # | ||
| + | ALTER TABLE log_db.log | ||
| + | ADD PARTITION ( | ||
| + | PARTITION p201811 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | ) | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | <file SQL alte_partition_von_Tabelle_weg.sql> | ||
| + | # | ||
| + | # Eine Partition löschen. | ||
| + | # | ||
| + | ALTER TABLE log_db.log | ||
| + | DROP | ||
| + | PARTITION p201811 | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | <file SQL alte_partition_von_Tabelle_kick.sql> | ||
| + | # | ||
| + | # Eine Partition löschen. | ||
| + | # | ||
| + | ALTER TABLE log_db.log | ||
| + | TRUNCATE | ||
| + | PARTITION p201811 | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Partitionierung einer Tabelle rotieren ==== | ||
| + | |||
| + | <file SQL Partitionen_der_Tabelle.sql> | ||
| + | # | ||
| + | # In diesem Block müssen alle benötigten Partitionen definiert sein, | ||
| + | # sollte hier eine Partition nicht aufgeführt sein, dann wird sie gelöscht! | ||
| + | # Neue hinzugekommene Partitionen werden angelegt. | ||
| + | # | ||
| + | ALTER TABLE log_db.log | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(zeitpunkt)) ( | ||
| + | PARTITION p201806 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201807 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201808 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201809 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p201810 VALUES LESS THAN (UNIX_TIMESTAMP(' | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ) | ||
| + | ; | ||
| + | </ | ||
| + | |||
| + | Leider kann man das rotieren von Partitionen nicht automatisch innerhalb der MySQL-DB mit einem EVENT einrichten, weil MySQL in der PARTITION-Sektion keine Variablen akzeptiert. | ||
| + | Es werden in der PARTITION-Sektion auch keine Funktionen akzeptiert, die sich auf eine Zeitzone beziehen wie z.B. '' | ||
| + | |||
| + | Deshalb ist die einzige Lösung, den SQL-Befehl " | ||
| + | Im folgenden stelle ich eine solche Lösung vor. | ||
| + | |||
| + | <file bash / | ||
| + | #!/bin/bash | ||
| + | #set -x | ||
| + | |||
| + | # | ||
| + | # | ||
| + | # Dieses Skript gibt das SQL-Querry aus, mit dem eine Tabelle partitioniert | ||
| + | # werden kann. | ||
| + | # Sollte hier eine Partition nicht mit angegeben worden sein, | ||
| + | # die aber vorhanden ist, dann wird sie gelöscht! | ||
| + | # Neu hinzugekommene Partitionen werden angelegt. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | VERSION=" | ||
| + | |||
| + | ANZAHL=" | ||
| + | DB_NAME=" | ||
| + | DB_TABELLE=" | ||
| + | PRI_SPALTE=" | ||
| + | |||
| + | # | ||
| + | |||
| + | if [ -z " | ||
| + | echo | ||
| + | echo "${0} [Datenbank] [Tabelle] [Spalte]" | ||
| + | echo " | ||
| + | exit 0 | ||
| + | fi | ||
| + | |||
| + | # | ||
| + | |||
| + | partitionen() | ||
| + | { | ||
| + | for i in $(seq 0 $((${ANZAHL}+1)) | tac) | ||
| + | do | ||
| + | #echo " | ||
| + | P_JAHR=" | ||
| + | P_MONAT=" | ||
| + | D_JAHR=" | ||
| + | D_MONAT=" | ||
| + | echo " | ||
| + | done | ||
| + | } | ||
| + | |||
| + | # | ||
| + | |||
| + | echo "# ${DB_NAME} / ${DB_TABELLE} / ${PRI_SPALTE}" | ||
| + | echo " | ||
| + | ALTER TABLE \`${DB_NAME}\`.\`${DB_TABELLE}\` | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(${PRI_SPALTE})) ( | ||
| + | $(partitionen) | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ) | ||
| + | ; | ||
| + | " | ||
| + | </ | ||
| + | |||
| + | Das obere Skript zeigt den SQL-Aufruf, um die Partitionierung einzurichten bzw. um sie regelmäßig zu aktualisieren. | ||
| + | ---- | ||
| + | Das folgende Skript führt dieses SQL-Kommando auch gleich auf die entsprechende Tabelle aus. | ||
| + | |||
| + | Bei jedem Aufruf wird die Tabellen-Partitionen-Konfiguration überprüft, | ||
| + | Das heißt, wenn eine Partition in der Tabelle vorhanden ist, die in der generierten Konfiguration __nicht__ vorhanden ist, dann wird sie __gelöscht__. | ||
| + | Wenn eine Partition in der Tabelle nicht vorhanden ist, die aber in der generierten Konfiguration vorhanden ist, dann wird sie neu angelegt. | ||
| + | |||
| + | Sinnvollerweise könnte man dieses Skript regelmäßig (z.B. täglich oder wöchentlich) von einem CRON-Job starten lassen. | ||
| + | |||
| + | <file bash / | ||
| + | #!/bin/bash | ||
| + | |||
| + | # | ||
| + | # | ||
| + | # Dieses Skript partitioniert die " | ||
| + | # | ||
| + | # Sollte hier eine Partition nicht mit angegeben werden, dann wird sie gelöscht! | ||
| + | # Neu hinzugekommene Partitionen werden angelegt. | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # echo " | ||
| + | # echo " | ||
| + | # | ||
| + | # | ||
| + | |||
| + | VERSION=" | ||
| + | |||
| + | ANZAHL=" | ||
| + | DB_PORT=" | ||
| + | DB_HOST=" | ||
| + | DB_NAME=" | ||
| + | DB_TABELLE=" | ||
| + | PRI_SPALTE=" | ||
| + | |||
| + | # | ||
| + | |||
| + | ### dieses Skript darf nur auf dem Master laufen | ||
| + | if [ "x$(ip a | fgrep " $(host ${DB_HOST} | awk '/has address/ | ||
| + | #echo "Diese Maschine ist nicht der Master. ABBRUCH" | ||
| + | exit 0 | ||
| + | fi | ||
| + | |||
| + | # | ||
| + | |||
| + | partitionen() | ||
| + | { | ||
| + | for i in $(seq 0 $((${ANZAHL}+1)) | tac) | ||
| + | do | ||
| + | #echo "# i=${i}" | ||
| + | P_JAHR=" | ||
| + | P_MONAT=" | ||
| + | D_JAHR=" | ||
| + | D_MONAT=" | ||
| + | echo " | ||
| + | done | ||
| + | } | ||
| + | |||
| + | # | ||
| + | |||
| + | echo " | ||
| + | ALTER TABLE \`${DB_NAME}\`.\`${DB_TABELLE}\` | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(${PRI_SPALTE})) ( | ||
| + | $(partitionen) | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ) | ||
| + | ; | ||
| + | " | mysql -P${DB_PORT} -h${DB_HOST} ${DB_NAME} | ||
| + | </ | ||
| + | |||
| + | Dieses Skript muss regelmäßig aufgerufen werden, midestens einmal pro Monat; in diesem Beispiel wird es täglich um ein Uhr aufgerufen: | ||
| + | > cat / | ||
| + | 0 1 * * * root / | ||
| + | |||
| + | //Wenn alles ordnungsgemäß läuft, dann sollten niemals Daten in der Partition " | ||
| + | > echo " | ||
| + | 0 | ||
| + | |||
| + | |||
| + | ==== Partitionen einer Tabelle mit einem MySQL-EVENT pflegen ==== | ||
| + | |||
| + | // | ||
| + | Die automatische Rotation der Tabellen-Partitionen kann durch einen externen CRON-Job erfolgen (siehe oben).\\ | ||
| + | \\ | ||
| + | Theoretisch sollte das aber komplett durch die MySQL mit Hilfe von EVENTS selber bewerkstelligt werden können - ich habe diverse Tests dazu durchgeführt und Doku gelesen; leider scheint die MySQL im PATITION-Block weder Variablen zu unterstützen, | ||
| + | \\ | ||
| + | Somit ist eine Automatisierung der Partitionsrotation durch EVENTS nicht möglich; evtl. könnte es mit Hilfe von anderen internen Prozeduren klappen, dazu fehlen mir aber aktuell die Kenntnisse. | ||
| + | // | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | # echo "SHOW VARIABLES LIKE ' | ||
| + | +-----------------+-------+ | ||
| + | | Variable_name | ||
| + | +-----------------+-------+ | ||
| + | | event_scheduler | OFF | | ||
| + | +-----------------+-------+ | ||
| + | |||
| + | Vorschlag für ein EVENT zur Partitionsrotation FIXME | ||
| + | <file sql_partitionen_der_tabelle_log> | ||
| + | USE `log_db`; | ||
| + | |||
| + | |||
| + | DROP PROCEDURE IF EXISTS prozedur_partitionen_der_tabelle_log; | ||
| + | DELIMITER | | ||
| + | CREATE PROCEDURE prozedur_partitionen_der_tabelle_log () | ||
| + | BEGIN | ||
| + | SET @yp1 = (SELECT DATE_FORMAT(DATE_ADD(CURDATE(), | ||
| + | SET @mp1 = (SELECT DATE_FORMAT(DATE_ADD(CURDATE(), | ||
| + | SET @dp1 = (UNIX_TIMESTAMP(CONCAT(@yp1, | ||
| + | SET @pp1 = (CONCAT(' | ||
| + | |||
| + | SET @y00 = (SELECT DATE_FORMAT(CURDATE(), | ||
| + | SET @m00 = (SELECT DATE_FORMAT(CURDATE(), | ||
| + | SET @d00 = (UNIX_TIMESTAMP(CONCAT(@y00, | ||
| + | SET @p00 = (CONCAT(' | ||
| + | |||
| + | SET @ym1 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm1 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm1 = (UNIX_TIMESTAMP(CONCAT(@ym1, | ||
| + | SET @pm1 = (CONCAT(' | ||
| + | |||
| + | SET @ym2 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm2 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm2 = (UNIX_TIMESTAMP(CONCAT(@ym2, | ||
| + | SET @pm2 = (CONCAT(' | ||
| + | |||
| + | SET @ym3 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm3 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm3 = (UNIX_TIMESTAMP(CONCAT(@ym3, | ||
| + | SET @pm3 = (CONCAT(' | ||
| + | |||
| + | SET @ym4 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm4 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm4 = (UNIX_TIMESTAMP(CONCAT(@ym4, | ||
| + | SET @pm4 = (CONCAT(' | ||
| + | |||
| + | SET @ym5 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm5 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm5 = (UNIX_TIMESTAMP(CONCAT(@ym5, | ||
| + | SET @pm5 = (CONCAT(' | ||
| + | |||
| + | SET @ym6 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @mm6 = (SELECT DATE_FORMAT(DATE_SUB(CURDATE(), | ||
| + | SET @dm6 = (UNIX_TIMESTAMP(CONCAT(@ym6, | ||
| + | SET @pm6 = (CONCAT(' | ||
| + | |||
| + | ALTER TABLE log_00 | ||
| + | PARTITION BY RANGE (UNIX_TIMESTAMP(c_time)) ( | ||
| + | @pp1, | ||
| + | @p00, | ||
| + | @pm1, | ||
| + | @pm2, | ||
| + | @pm3, | ||
| + | @pm4, | ||
| + | @pm5, | ||
| + | @pm6, | ||
| + | PARTITION p0 VALUES LESS THAN MAXVALUE | ||
| + | ); | ||
| + | END | | ||
| + | DELIMITER ; | ||
| + | |||
| + | |||
| + | DROP EVENT IF EXISTS event_partitionen_der_tabelle_log; | ||
| + | |||
| + | CREATE EVENT event_partitionen_der_tabelle_log | ||
| + | ON SCHEDULE | ||
| + | AT CURRENT_TIMESTAMP + INTERVAL 1 DAY | ||
| + | DO | ||
| + | CALL prozedur_partitionen_der_tabelle_log(); | ||
| + | </ | ||
| + | |||
