Inhaltsverzeichnis
In diesem Kapitel geht es um die in MySQL 5.1 implementierten Formen der Partitionierung. Eine Einführung in Partitionierung und Partitionierungskonzepte finden Sie in Abschnitt 17.1, „Überblick über die Partitionierung in MySQL“. MySQL 5.1 unterstützt mehrere Formen der Partitionierung, die in Abschnitt 17.2, „Partitionstypen“, beschrieben werden, sowie der Teilpartitionierung (auch als zusammengesetzte Partitionierung bezeichnet), die in Abschnitt 17.2.5, „Unterpartitionen“, beschrieben werden. Wie Partitionen in partitionierten Tabellen hinzugefügt, entfernt oder geändert werden, erfahren Sie in Abschnitt 17.3, „Partitionsverwaltung“. Tabellenwartungsbefehle für partitionierte Tabellen behandeln wir in Abschnitt 17.3.3, „Wartung von Partitionen“.
Wichtig: Partitionierte Tabellen,
die mit den MySQL-Versionen vor 5.1.6 angelegt wurden, können von
einem MySQL Server der Version 5.1.6 oder höher nicht gelesen
werden. Außerdem kann die
INFORMATION_SCHEMA.TABLES
-Tabelle nicht benutzt
werden, wenn solche Tabellen auf einem Server liegen, der mit der
Version 5.1.6 oder höher betrieben wird. Wenn Sie partitionierte
Tabellen haben, die mit MySQL 5.1.5 oder früher angelegt wurden,
lesen Sie unbedingt die Zusatzinformationen und empfohlenen
Workarounds in Abschnitt D.1.1, „Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)“, nach,
bevor Sie auf MySQL 5.1.6 oder höher
aufrüsten.
Die Partitionierungsimplementierung in MySQL 5.1 befindet sich noch
in der Entwicklung und ist noch nicht bereit für
Produktionsumgebungen. Etwas Ähnliches gilt für den Inhalt dieses
Kapitels: Manche der hier beschriebenen Features sind in
Wirklichkeit noch gar nicht implementiert, und andere funktionieren
noch nicht ganz so wie beschrieben (beispielsweise die Optionen
DATA DIRECTORY
und INDEX
DIRECTORY
für Partitionen, die noch unter dem Bug#13520
leiden). Wir haben versucht, diese Abweichungen im vorliegenden
Kapitel kenntlich zu machen. Bitte schauen Sie in folgende Quellen
hinein, bevor Sie uns Bugreports schicken:
Dies ist das offizielle Diskussionsforum für alle, die sich für die Partitionierungstechnologie von MySQL interessieren oder damit arbeiten. Hier finden Sie Ankündigungen und Aktualisierungen von MySQL-Entwicklern und anderen. Das Forum wird von den Mitgliedern des Partitioning Development and Documentation-Teams geleitet.
Eine Liste aller Partitionierungs-Bugs, die an unser Bugs-System gemeldet wurden, unabhängig von Alter, Ernsthaftigkeit und aktuellem Status. Es ist möglich, diese Liste nach diversen Kritierien zu filtern. Eventuell können Sie auch auf die MySQL Bugs System Home Page gehen und nach Bugs fahnden, die für Sie von besonderem Interesse sind.
Der MySQL Partitioning Architect und Lead Developer Mikael Ronström stellt hier häufig Artikel ein, die seine Arbeit mit MySQL Partitioning und MySQL Cluster betreffen.
Eine News-Site über MySQL mit Blogs, die für jeden MySQL-Nutzer interessant sein dürften. Wir raten Ihnen, hier Links zu den Blogs der Nutzer herauszusuchen, die mit der Partitionierung in MySQL arbeiten, oder Ihr eigenes Blog eintragen zu lassen.
Die Alpha-Binaries von MySQL 5.1 stehen nun unter
http://dev.mysql.com/downloads/mysql/5.1.html zum
Herunterladen zur Verfügung. Die Quelle für die aktuellsten
Bugfixes und neuen Features im Zusammenhang mit Partitionierung
finden Sie allerdings in unserem BitKeeper-Repository. Um
Partitionierung zu ermöglichen, müssen Sie den Server mit der
Option --with-partition
kompilieren. Weitere
Informationen über den MySQL-Build finden Sie unter
Abschnitt 2.8, „Installation der Quelldistribution“. Wenn Sie Probleme mit dem
Kompilieren eines partitionierungsfähigen MySQL 5.1-Build haben,
schauen Sie in das MySQL
Partitioning Forum und fragen Sie dort um Hilfe, falls nicht
bereits eine Lösung für Ihr Problem veröffentlicht wurde.
Dieser Abschnitt gibt einen Überblick über Partitionierungskonzepte in MySQL 5.1.
Beschränkungen der Partitionierung und die Grenzen des Features erfahren Sie unter Abschnitt 17.4, „Beschränkungen und Grenzen der Partitionierung“.
Der SQL-Standard enthält kaum Anleitungen in Bezug auf die
physikalischen Aspekte der Datenspeicherung. Die Sprache SQL ist
dafür ausgelegt, unabhängig von Datenstrukturen, Medien sowie
den einem Schema zugrunde liegenden Tabellen, Zeilen oder Spalten
zu funktionieren. Allerdings haben die meisten modernen
Datenbankmanagementsysteme auch irgendwelche Möglichkeiten
entwickelt, um festzustellen, an welchem Ort (Dateisystem,
Hardware oder beides) bestimmte Daten physikalisch gespeichert
werden. In MySQL unterstützte die Speicher-Engine
InnoDB
lange Zeit Tablespaces und der MySQL
Server konnte schon vor der Einführung von Partitionierung so
konfiguriert werden, dass er für die Speicherung
unterschiedlicher Datenbanken verschiedene physikalische
Verzeichnisse verwendete (unter Abschnitt 7.6.1, „Symbolische Verknüpfungen“,
werden die Gründe dafür erklärt).
Mit der Partitionierung wird dieses Konzept
noch einen Schritt weitergeführt: Hiermit können Sie
verschiedene Teile einzelner Tabellen über ein Dateisystem
verteilen, und zwar nach Regeln, die Sie im Großen und Ganzen
nach Ihren Bedürfnissen festlegen. So werden verschiedene Teile
einer Tabelle im Endeffekt als getrennte Tabellen an verschiedenen
Stellen gespeichert. Die vom Benutzer gewählte Regel, nach
welcher die Daten aufgeteilt werden, bezeichnet man als
Partitionierungsfunktion. Diese kann in
MySQL der Modulus sein, ein einfacher Vergleich mit einer Menge
von Wertebereichen oder Wertelisten, oder auch eine interne oder
lineare Hash-Funktion. Die Funktion wird je nach dem vom Benutzer
angegebenen Partitionierungstyp ausgewählt und nimmt den Wert
eines ebenfalls vom Benutzer gelieferten Ausdrucks als Parameter
entgegen. Dieser Ausdruck kann der Wert einer Integer-Spalte sein
oder auch eine Funktion, die auf einer oder mehreren Spalten
arbeitet und einen Integer zurückgibt. Der Wert dieses Ausdrucks
wird an die Partitionierungsfunktion übergeben, die ihrerseits
die Nummer der Partition, in welcher dieser spezielle Datensatz
gespeichert werden soll, als Integer zurückgibt. Diese Funktion
muss nichtkonstant und nichtzufällig sein. Sie darf keine
Anfragen enthalten, kann aber jedweden in MySQL zulässigen
SQL-Ausdruck enthalten, wenn dieser nur einen positiven Integer
kleiner MAXVALUE
zurückgibt (dies ist der
größtmögliche positive Integer). Beispiele für
Partitionierungsfunktionen finden Sie in den Abschnitten über
Partitionierungstypen weiter unten in diesem Kapitel (siehe
Abschnitt 17.2, „Partitionstypen“) sowie in den Beschreibungen
zur Partitionierungssyntax in Abschnitt 13.1.5, „CREATE TABLE
“.
Dies bezeichnet man als horizontale Partitionierung: Verschiedene Zeilen einer Tabelle können unterschiedlichen physikalischen Partitionen zugewiesen werden. MySQL 5.1 kennt keine vertikale Partitionierung, bei der verschiedene Tabellenspalten auf verschiedene physikalische Partitionen gespeichert würden. Es gibt auch noch keinerlei Pläne, vertikale Partitionierung in MySQL 5.1 einzuführen.
Partitionierungsunterstützung ist in den
-max
-Releases von MySQL 5.1
enthalten (d. h., dass die 5.1--max
-Binaries
mit der Option --with-partition
erstellt werden).
Wenn die MySQL-Binary mit Partitionierungsunterstützung gebaut
wird, muss nichts weiter unternommen werden, um diese zu
aktivieren (es sind beispielsweise keine speziellen Einträge in
der my.cnf
-Datei erforderlich). Ob Ihr MySQL
Server Partitionierung unterstützt, verrät Ihnen der Befehl
SHOW VARIABLES
:
mysql> SHOW VARIABLES LIKE '%partition%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| have_partitioning | YES |
+-------------------+-------+
1 row in set (0.00 sec)
Wenn Sie in der Ausgabe Ihres ensprechenden SHOW
VARIABLES
-Befehls nicht wie hier eine
have_partitioning
-Variable mit dem Wert
YES
zu sehen bekommen, dann unterstützt Ihre
MySQL-Version keine Partitionierung.
Vor MySQL 5.1.6 hieß diese Variable
have_partition_engine
(Bug#16718).
Um partitionierte Tabellen zu erstellen, können Sie jede vom
MySQL Server unterstützte Speicher-Engine einsetzen; die
MySQL-Partitionierungs-Engine läuft in ihrer eigenen Schicht und
kann mit allen diesen Speicher-Engines umgehen. In MySQL
5.1 müssen alle Partitionen derselben
partitionierten Tabelle auch dieselbe Speicher-Engine benutzen.
Sie können beispielsweise nicht für die eine Partition
MyISAM
und für die andere
InnoDB
benutzen. Allerdings hindert nichts Sie
daran, verschiedene Speicher-Engines für verschiedene
partitionierte Tabellen auf demselben MySQL Server oder sogar in
derselben Datenbank zu benutzen.
Um eine bestimmte Speicher-Engine für eine partitionierte Tabelle
zu verwenden, müssen Sie lediglich die passende
[STORAGE] ENGINE
-Option einstellen, wie Sie es
auch bei einer nichtpartitionierten Tabelle tun würden.
Allerdings müssen Sie daran denken, dass [STORAGE]
ENGINE
(und andere Tabellenoptionen) in einer
CREATE TABLE
-Anweisung vor
den Partitionierungsoptionen stehen müssen. Das folgende Beispiel
zeigt, wie man eine Tabelle anlegt, die per Hash in 6 Partitionen
zerlegt wird und die Speicher-Engine InnoDB
verwendet:
CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE) ENGINE=INNODB PARTITION BY HASH(MONTH(tr_date)) PARTITIONS 6;
(Beachten Sie, dass jede PARTITION
-Klausel auch
eine [STORAGE] ENGINE
-Option enthalten kann,
die jedoch in MySQL 5.1 wirkungslos bleibt.)
Es ist durchaus möglich, auch partitionierte temporäre Tabellen zu erstellen, doch diese haben nur so lange wie die aktuelle MySQL-Session Bestand. Dasselbe gilt für nichtpartitionierte temporäre Tabellen.
Hinweis: Eine Partitionierung betrifft alle Daten und Indizes einer Tabelle. Sie können weder die Daten ohne ihre Indizes partitionieren noch die Indizes ohne die Daten, ebenso wenig, wie Sie nur einen Teil einer Tabelle partitionieren können.
Die Daten und Indizes jeder Partition können mit den Optionen
DATA DIRECTORY
und INDEX
DIRECTORY
der PARTITION
-Klausel der
CREATE TABLE
-Anweisung, mit der die
partitionierte Tabelle angelegt wird, einem bestimmten Verzeichnis
zugewiesen werden. Überdies können Sie mit
MAX_ROWS
und MIN_ROWS
festlegen, wie viele Zeilen höchstens bzw. mindestens in jeder
Partition gespeichert werden dürfen. Genaueres über diese
Optionen erfahren Sie unter
Abschnitt 17.3, „Partitionsverwaltung“.
Hinweis: Dieses Feature läuft
zurzeit wegen Bug#13250 nicht; dies dürfte jedoch behoben sein,
wenn die ersten 5.1-Binaries zur Verfügung gestellt werden.
Eine Partitionierung hat folgende Vorteile:
In einer einzigen Tabelle können mehr Daten gespeichert werden, als auf eine einzelne Festplatte oder Dateisystempartition passen.
Unnütz gewordene Daten lassen sich oft einfacher aus der Tabelle entfernen, wenn man nur eine Partition löschen muss, die ebendiese Daten enthält. Umgekehrt lassen sich in einigen Fällen Daten auch einfacher hinzufügen, indem man einfach eine neue Partition speziell für diese Daten erschafft.
Normalerweise bietet eine Partitionierung auch noch die in der folgenden Liste aufgeführten Vorteile. Diese Features sind zwar in MySQL Partitioning noch nicht implementiert, stehen aber ganz oben auf unserer Prioritätenliste. Wir hoffen, sie im Produktionsrelease der Version 5.1 bereits einbringen zu können.
Manche Anfragen lassen sich dadurch optimieren, dass die
Daten, die auf eine WHERE
-Klausel
zutreffen, auf bestimmten Partitionen gespeichert werden
können, wodurch die restlichen Partitionen von der Suche
ausgeschlossen bleiben. Da Partitionen nach der Erstellung
einer partitionierten Tabelle geändert werden können, sind
Sie in der Lage, Ihre Daten so zu reorganisieren, dass
häufige Anfragen schneller verarbeitet werden, als es im
ursprünglichen Partitionierungsschema der Fall war.
Anfragen mit Aggregatfunktionen wie SUM()
und COUNT()
lassen sich leicht
parallelisieren. Ein einfaches Beispiel einer solchen Anfrage
wäre SELECT salesperson_id, COUNT(orders) as
order_total FROM sales GROUP BY salesperson_id;
. Mit
„parallelisieren“ ist gemeint, dass die Anfrage
auf allen Partitionen gleichzeitig ausgeführt werden kann und
das Endergebnis dann die Summe der Resultate der einzelnen
Partitionen ist.
Da Suchoperationen auf mehrere Festplatten verteilt werden können, wird ein größerer Durchsatz an Anfragen erzielt.
Bitte schauen Sie regelmäßig im englischsprachingen Handbuch, Kapitel „Partitions“, nach aktuellen Entwicklungen in der Implementierung der Partitionierung in MySQL 5.1, da diese Entwicklung noch nicht abgeschlossen ist.
Dieser Abschnitt beschreibt die in MySQL 5.1 verfügbaren Arten der Partitionierung, nämlich:
RANGE
-Partitionierung
(Bereichspartitionierung): Weist den Partitionen Zeilen zu, je
nachdem, ob ihre Spaltenwerte in einen bestimmten Wertebereich
fallen. Siehe Abschnitt 17.2.1, „RANGE
-Partitionierung“.
LIST
-Partitionierung
(Listenpartitionierung): Ähnelt der Bereichspartitionierung,
nur dass hier die Partition anhand der Frage ausgewählt wird,
ob sich die Spaltenwerte in einer Menge eigenständiger Werte
wiederfinden. Siehe Abschnitt 17.2.2, „LIST
-Partitionierung“.
HASH
-Partitionierung:
Hierbei wird eine Partition anhand des Rückgabewerts eines
benutzerdefinierten Ausdrucks ausgewählt, der auf
Spaltenwerten der Zeilen operiert, die in die Tabelle
eingefügt werden sollen. Die Funktion kann jeden in MySQL
zulässigen Ausdruck enthalten, der einen nichtnegativen
Integer ergibt. Siehe Abschnitt 17.2.3, „HASH
-Partitionierung“.
KEY
-Partitionierung
(Schlüsselpartitionierung): Ähnelt der Hash-Partitionierung,
aber mit dem Unterschied, dass nur bestimmte auszuwertende
Spalten übergeben werden und der MySQL Server seine eigene
Hash-Funktion liefert. Die Spalte(n) dürfen nur Integer-Werte
enthalten. Siehe Abschnitt 17.2.4, „KEY
-Partitionierung“.
Bitte vergessen Sie nicht: Egal welche Art von Partitionierung Sie
verwenden, Partitionen werden immer automatisch der Reihe nach bei
ihrer Erstellung durchnummeriert, und zwar beginnend mit
0
. Wenn eine neue Zeile in eine partitionierte
Tabelle eingefügt wird, wird die richtige Partition anhand dieser
laufenden Nummern gefunden. Wenn beispielsweise Ihre Tabellen 4
Partitionen nutzen, so habe diese Partitionen die Nummern
0
, 1
, 2
und 3
. Bei einer RANGE
- oder
LIST
-Partitionierung müssen Sie
gewährleisten, dass für jede Partitionsnummer auch eine
Partition definiert ist. Bei einer
HASH
-Partitionierung muss die verwendete
benutzerdefinierte Funktion einen Integer größer
0
zurückgeben. Bei einer
KEY
-Partitionierung wird dieses Problem
automatisch von der Hash-Funktion gelöst, die der MySQL Server
intern einsetzt.
Partitionsnamen halten sich generell an dieselben Regeln, die auch
für andere MySQL-Bezeichner gelten, wie beispielsweise die für
Tabellen und Datenbanken. Allerdings müssen Sie daran denken,
dass Partitionsnamen nicht zwischen Groß- und Kleinschreibung
unterscheiden. So würde beispielsweise die folgende
CREATE TABLE
-Anweisung scheitern:
mysql>CREATE TABLE t2 (val INT)
->PARTITION BY LIST(val)(
->PARTITION mypart VALUES IN (1,3,5),
->PARTITION MyPart VALUES IN (2,4,6)
->);
ERROR 1488 (HY000): All partitions must have unique names in the table
Der Fehler liegt daran, dass MySQL keinen Unterschied zwischen den
Partitionsnamen mypart
und
MyPart
erkennen kann.
In den folgenden Abschnitten geben wir nicht immer alle nur
denkbaren Syntaxvarianten zur Erstellung der Partitionstypen an.
Diese Informationen können Sie unter
Abschnitt 13.1.5, „CREATE TABLE
“, nachschlagen.
Wenn eine Tabelle nach Wertebereichen partitioniert wird,
enthält später jede Partition die Zeilen, für die der
Partitionierungsausdruck einen Wert hat, der in einem bestimmten
Wertebereich liegt. Die Wertebereiche sollten aneinander
grenzen, aber sich nicht überschneiden, und sie sollten mit dem
VALUES LESS THAN
-Operator definiert werden.
Bei den nächsten Beispielen gehen wir davon aus, dass wie unten
beschrieben eine Tabelle für die Personaldaten einer Kette von
20 Videotheken (mit den Nummern 1 bis 20) eingerichtet wird:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT NOT NULL, store_id INT NOT NULL );
Diese Tabelle kann je nach Bedarf auf unterschiedliche Weise
nach Bereichen partitioniert werden. Eine Möglichkeit wäre es,
die store_id
-Spalte zu verwenden. Sie
könnten die Tabelle beispielsweise mit einer PARTITION
BY RANGE
-Klausel auf 4 Partitionen verteilen:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT NOT NULL, store_id INT NOT NULL ) PARTITION BY RANGE (store_id) ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11), PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN (21) );
In diesem Partitionierungsschema werden die Angestelltendaten
der Zweigstellen 1 bis 5 in Partition p0
gespeichert, die Angestelltendaten der Zweigstellen 6 bis 10 in
Partition p1
und so weiter. Beachten Sie,
dass die Partitionen der Reihe nach von der niedrigsten bis zur
höchsten Nummer definiert werden. Dies verlangt die Syntax von
PARTITION BY RANGE
, die in dieser Hinsicht
einer switch ... case
-Anweisung in C oder
Java ähnelt.
Es ist einfach, festzustellen, dass eine neue Zeile mit den
Daten (72, 'Michael', 'Widenius', '1998-06-25', NULL,
13)
in die Partition p2
eingefügt
wurde, doch was geschieht, wenn die Videothekenkette eine 21.
Zweigstelle eröffnen möchte? In dem vorliegenden Schema gibt
es keine Regeln für Zeilen mit einer
store_id
größer 20. Daher wird ein Fehler
gemeldet, weil der Server nicht weiß, wohin damit. Dieses
Verhalten können Sie mit einem so genannten
„Catchall“ verhindern: einer VALUES LESS
THAN
-Klausel in der CREATE
TABLE
-Anweisung, die für alle Werte Vorsorge trifft,
die den größten explizit angegebenen Wert übersteigen:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
MAXVALUE
ist der größte mögliche
Integer-Wert. Nun werden alle Zeilen, deren
store_id
-Spaltenwert größer oder gleich dem
größten definierten Wert 16 ist, in Partition
p3
gespeichert. Irgendwann einmal, wenn die
Anzahl der Zweigstellen auf 25, 30 oder mehr angewachsen ist,
können Sie mit einer ALTER TABLE
-Anweisung
neue Partitionen für die Zweigstellen 21 bis 25, 26 bis 30 und
so weiter hinzufügen (Einzelheiten zur Vorgehensweise finden
Sie unter Abschnitt 17.3, „Partitionsverwaltung“.)
In ähnlicher Weise können Sie die Tabelle auf der Grundlage
von Job-Codes partitionieren, d. h. anhand der Werte der Spalte
job_code
. Nehmen wir beispielsweise an,
reguläre (in der Filiale arbeitende) Angestellte haben einen
zweistelligen Job-Code, Büro- und Support-Mitarbeiter einen
dreistelligen und Manager einen vierstelligen. Dann könnten Sie
Ihre partitionierte Tabelle folgendermaßen definieren:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT NOT NULL, store_id INT NOT NULL ) PARTITION BY RANGE (job_code) ( PARTITION p0 VALUES LESS THAN (100), PARTITION p1 VALUES LESS THAN (1000), PARTITION p2 VALUES LESS THAN (10000) );
In diesem Beispiel würden die Daten der Filialmitarbeiter in
der Partition p0
, die der Büro- und
Support-Mitarbeiter in der Partition p1
und
die der Manager in der Partition p2
gespeichert.
In VALUES LESS THAN
-Klauseln kann auch ein
Ausdruck verwendet werden, allerdings nur mit der Maßgabe, dass
MySQL in der Lage sein muss, den Rückgabewert dieses Ausdrucks
in einem LESS THAN
(<
)-Vergleich auszuwerten; der Wert des
Ausdrucks darf also nicht NULL
sein. Dies ist
der Grund, weshalb die Spalten hired
,
separated
, job_code
und
store_id
der Tabelle
employees
als NOT NULL
definiert wurden.
Anstatt die Tabellendaten anhand der Zweigstellennummer zu
verteilen, können Sie auch einen Ausdruck verwenden, der auf
den beiden DATE
-Spalten basiert. Nehmen wir
beispielsweise an, Sie möchten die Tabelle nach dem Jahr
partitionieren, in welchem die Mitarbeiter das Unternehmen
verlassen, also nach dem Wert der Spalte
YEAR(separated)
. Folgende CREATE
TABLE
-Anweisung würde ein solches
Partitionierungsschema implementieren:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT ) PARTITION BY RANGE ( YEAR(separated) ) ( PARTITION p0 VALUES LESS THAN (1991), PARTITION p1 VALUES LESS THAN (1996), PARTITION p2 VALUES LESS THAN (2001), PARTITION p3 VALUES LESS THAN MAXVALUE );
In diesem Schema werden die Daten der Mitarbeiter, die das
Unternehmen vor 1991 verließen, in der Partition
p0
gespeichert, die Daten derjenigen, die
zwischen 1991 und 1995 gingen, in Partition
p1
, die Daten derjenigen, die zwischen 1996
und 2000 gingen, in Partition p2
und die
Daten derjenigen, die nach 2000 gingen, in Partition
p3
.
Eine Bereichspartitionierung ist in folgenden Fällen besonders nützlich:
Sie möchten oder müssen „alte“ Daten
löschen. Wenn Sie das soeben gezeigte
Partitionierungsschema umsetzen, brauchen Sie nur noch
ALTER TABLE employees DROP PARTITION p0;
aufzurufen, um alle Datensätze der Angestellten zu
löschen, die vor 1991 das Unternehmen verlassen haben.
(Weitere Informationen finden Sie unter
Abschnitt 13.1.2, „ALTER TABLE
“, und
Abschnitt 17.3, „Partitionsverwaltung“.) Wenn Sie eine
Tabelle mit sehr vielen Zeilen haben, kann diese
Vorgehensweise sehr viel effizienter als eine
DELETE
-Anfrage wie etwa DELETE
FROM employees WHERE YEAR(separated) <= 1990;
sein.
Sie möchten eine Spalte benutzen, die Datums- oder Uhrzeitwerte oder Werte aus einer anderen Wertfolge enthält.
Es werden oft Anfragen ausgeführt, die direkt von einer
für die Partitionierung der Tabelle verwendeten Spalte
abhängen. So kann MySQL beispielsweise bei einer Anfrage
wie SELECT COUNT(*) FROM employees WHERE
YEAR(separated) = 2000 GROUP BY store_id;
ganz
schnell herausfinden, dass nur die Partition
p2
durchsucht werden muss, da die
restlichen Partitionen gar keine zu der
WHERE
-Klausel passenden Einträge
enthalten können. Hinweis:
Dies Optimierung wurde in den Quelldateien von MySQL 5.1
zwar noch nicht aktiviert, aber wir arbeiten daran.
Die Listenpartitionierung in MySQL ähnelt in vieler Hinsicht
der Bereichspartitionierung. Wie bei dieser muss jede Partition
explizit definiert werden. Der Hauptunterschied besteht darin,
dass bei einer Listenpartitionierung die einzelnen Partitionen
anhand der Frage gebildet werden, ob ein Spaltenwert in einer
von mehreren Wertelisten vorkommt, während
bei der Bereichspartitionierung gefragt wird, ob er in einer von
mehreren Wertefolgen vorkommt. Diese Form
der Partitionierung nehmen Sie mit PARTITION BY
LIST(
vor, wobei
expr
)expr
ein Spaltenwert oder ein auf
einem Spaltenwert basierender Ausdruck ist, der einen Integer
zurückgibt. Die einzelnen Partitionen werden sodann durch
VALUES IN
(
definiert,
wobei value_list
)value_list
eine kommagetrennte
Liste von Integern ist.
Hinweis: In MySQL
5.1 kann der Spaltenwert bei einer
LIST
-Partitionierung nur mit einer
Integer-Liste verglichen werden.
Im Gegensatz zu Bereichspartitionen müssen Listenpartitionen
nicht in einer bestimmten Reihenfolge definiert werden. Genauere
Hinweise zur Syntax finden Sie unter
Abschnitt 13.1.5, „CREATE TABLE
“.
In den nachfolgenden Beispielen gehen wir davon aus, dass die
Grunddefinition der zu partitionierenden Tabelle die der
nachfolgenden CREATE TABLE
-Anweisung ist:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT );
(Dies ist dieselbe Tabelle, die auch als Grundlage der Beispiele
in Abschnitt 17.2.1, „RANGE
-Partitionierung“, diente.)
Angenommen, wir haben eine Kette von 20 Videotheken, die auf 4 Franchisenehmer verteilt ist, wie in der folgenden Tabelle gezeigt:
Region | Store ID Numbers |
North | 3, 5, 6, 9, 17 |
East | 1, 2, 10, 11, 19, 20 |
West | 4, 12, 13, 14, 18 |
Central | 7, 8, 15, 16 |
Um diese Tabelle so zu partitionieren, dass jeweils die
Zweigstellen einer Region zusammenhängend gespeichert werden,
könnten Sie die folgende CREATE
TABLE
-Anweisung einsetzen:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT ) PARTITION BY LIST(store_id) ( PARTITION pNorth VALUES IN (3,5,6,9,17), PARTITION pEast VALUES IN (1,2,10,11,19,20), PARTITION pWest VALUES IN (4,12,13,14,18), PARTITION pCentral VALUES IN (7,8,15,16) );
Nun ist es ganz einfach, regionale Angestelltendaten in die
Tabelle zu laden oder aus ihr zu löschen. Nehmen wir
beispielsweise an, alle Zweigstellen der Region West werden an
ein anderes Unternehmen verkauft. Dann könnten alle
Angestelltendaten der Zweigstellen dieser Region mit der Anfrage
ALTER TABLE employees DROP PARTITION pWest;
gelöscht werden, die viel schneller als die entsprechende
DELETE
-Anfrage DELETE FROM employees
WHERE store_id IN (4,12,13,14,18);
ausgeführt wird.
Wichtig: Wenn Sie versuchen,
eine Zeile einzufügen, deren Spaltenwert (oder Rückgabewert
für den Partitionierungsausdruck) in den Listen mit den
Partitionierungswerten nicht vorkommt, scheitert die
INSERT
-Anfrage mit einer Fehlermeldung. So
würde beispielsweise die folgende Anfrage bei dem oben
skizzierten Schema einer LIST
-Partitionierung
fehlschlagen:
INSERT INTO employees VALUES (224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 42, 21);
Dieser Fehler tritt ein, da der
store_id
-Spaltenwert 21
in
keiner der Wertelisten auftritt, die zur Definition der
Partitionen pNorth
, pEast
,
pWest
und pCentral
angegeben wurden. Es ist wichtig zu wissen, dass für
Listenpartitionen keine „Catchall“-Definition wie
VALUES LESS THAN MAXVALUE
existiert, um Werte
unterzubringen, die in keiner der Wertelisten auftauchen. Mit
anderen Worten: Jeder Partitionierungswert muss in
einer der Wertelisten vorhanden sein.
Wie die RANGE
-Partitionierung kann auch die
LIST
-Partitionierung mit einer Hash- oder
Schlüsselpartitionierung kombiniert werden, um eine
zusammengesetzte Partitionierung (Teilpartitionierung) zu
bilden. Siehe Abschnitt 17.2.5, „Unterpartitionen“.
Eine Partitionierung nach HASH
wird
hauptsächlich eingesetzt, um eine gleichmäßige Verteilung der
Daten auf eine im Voraus festgelegte Anzahl von Partitionen zu
erzielen. Bei einer Bereichs- oder Listenpartitionierung müssen
Sie explizit angeben, in welcher Partition Spaltenwerte
gespeichert werden sollen, während MySQL Ihnen dies bei einer
Hash-Partitionierung abnimmt. Hier müssen Sie lediglich einen
Spaltenwert oder einen auf einem Spaltenwert basierenden
Ausdruck für den Hash angeben und sagen, auf wie viele
Partitionen die partitionierte Tabelle verteilt werden soll.
Um eine Tabelle mit einer
HASH
-Partitionierung aufzuteilen, müssen Sie
an die CREATE TABLE
-Anweisung eine
PARTITION BY HASH
(
-Klausel anfügen,
wobei expr
)expr
ein Ausdruck ist, der
einen Integer zurückgibt. Das kann auch einfach der Name einer
Spalte sein, die einen der Integer-Typen von MySQL hat.
Zusätzlich wird normalerweise noch eine PARTITIONS
-Klausel angefügt,
wobei num
num
ein nichtnegativer Integer
ist und angibt, auf wie viele Partitionen die Tabelle verteilt
werden soll.
Die folgende Anweisung erzeugt beispielsweise eine Tabelle, die
einen Hash der Spalte store_id
verwendet und
auf 4 Partitionen verteilt wird:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT ) PARTITION BY HASH(store_id) PARTITIONS 4;
Wenn Sie keine PARTITIONS
-Klausel verwenden,
ist die Anzahl der Partitionen nach Voreinstellung
1
. Ausnahme:
Bei NDB Cluster
-Tabellen ist die vorgegebene
Anzahl der Partitionen gleich der Anzahl der Datenknoten im
Cluster, eventuell berichtigt um eine
MAX_ROWS
-Einstellung, um zu gewährleisten,
dass alle Zeilen in die Partitionen hineinpassen. (Siehe
Kapitel 16, MySQL Cluster.)
Wenn Sie das Schlüsselwort PARTITIONS
ohne
darauf folgende Zahlenangabe verwenden, wird ein Syntaxfehler
ausgelöst.
Sie können für expr
auch einen
SQL-Ausdruck einsetzen, der einen Integer zurückliefert. Wenn
Sie Ihre Tabelle beispielsweise anhand des Einstellungsjahres
der Angestellten partitionieren möchten, gehen Sie
folgendermaßen vor:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT ) PARTITION BY HASH( YEAR(hired) ) PARTITIONS 4;
Sie können für expr
alle Funktionen
und Ausdrücke verwenden, die in MySQL zulässig sind,
vorausgesetzt, der Rückgabewert ist ein nichtkonstanter,
nichtzufälliger Integer. (Mit anderen Worten: Der Wert soll
variieren, aber deterministisch sein.) Sie müssen allerdings
daran denken, dass dieser Ausdruck jedes Mal, wenn eine Zeile
eingefügt, aktualisiert oder eventuell auch gelöscht wird,
ausgewertet werden muss. Das bedeutet, dass komplexe Ausdrücke
die Leistung beeinträchtigen können, insbesondere, wenn
Operationen ausgeführt werden, die viele Zeilen auf einmal
betreffen (wie etwa Masseneinfügungen).
Am effizientesten sind Hash-Funktionen, die nur eine einzige Tabellenspalte bearbeiten und deren Wert mit dem Spaltenwert konsistent zu- oder abnimmt, da hierdurch ein „Pruning“ von Partitionsbereichen möglich wird. D. h.: Je enger sich der Wert des Ausdrucks an dem Wert der zugrunde liegenden Spalte orientiert, umso effizienter kann MySQL ihn für die Hash-Partitionierung einsetzen.
Wenn beispielsweise date_col
eine Spalte vom
Typ DATE
ist, dann ändert sich der Ausdruck
TO_DAYS(date_col)
unmittelbar mit dem Wert
von date_col
, da jede Änderung des Werts von
date_col
auch den Wert des Ausdrucks ändert,
und zwar in völlig konsistenter Form. Der Ausdruck
YEAR(date_col)
ändert sich bei
date_col
-Änderungen nicht ganz so
unmittelbar wie TO_DAYS(date_col)
, da nicht
jede Änderung in date_col
eine entsprechende
Änderung in YEAR(date_col)
nach sich zieht.
Dennoch ist auch YEAR(date_col)
ein guter
Kandidat für eine Hash-Funktion, da es sich direkt mit einem
Teil von date_col
ändert und nicht die
Gefahr besteht, dass eine Änderung von
date_col
zu einer unverhältnismäßigen
Änderung von YEAR(date_col)
führt.
Nehmen wir dagegen an, Sie hätten eine Spalte namens
int_col
vom Typ INT
. Nun
betrachten Sie den Ausdruck POW(5-int_col,3) +
6
. Dieser wäre ganz schlecht als Hash-Funktion
geeignet, da nicht garantiert ist, dass Änderungen von
int_col
proportionale Änderungen im Wert des
Ausdrucks nach sich ziehen. Wenn Sie den Wert von
int_col
um einen gegebenen Betrag ändern,
können dadurch ganz unterschiedliche Änderungen im Wert des
Ausdrucks eintreten. Ändern Sie beispielsweise
int_col
von 5
in
6
, so ändert sich der Wert des Ausdrucks um
-1
, ändern Sie dagegen
int_col
von 6
in
7
, so ändert sich der Wert des Ausdrucks um
-7
.
Mit anderen Worten: Je enger der Graph des Spaltenwerts im
Verhältnis zum Wert des Ausdrucks einer geraden Linie folgt,
wie sie durch die Gleichung
y=
vorgegeben
ist, wenn n
xn
eine von null
verschiedene Konstante ist, umso besser eignet sich der Ausdruck
für das Hashing. Denn je weniger linear ein Ausdruck ist, umso
ungleichmäßiger werden die Daten auf die Partitionen verteilt,
die dieser Ausdruck anlegt.
Theoretisch ist bei Ausdrücken, an denen mehrere Spaltenwerte beteiligt sind, auch Pruning möglich, aber es kann schwierig und langwierig sein, herauszufinden, welche dieser Ausdrücke nun wirklich für Pruning geeignet sind. Daher sind Hashing-Ausdrücke mit mehreren Spalten nicht sonderlich zu empfehlen.
Wenn PARTITION BY HASH
verwendet wird,
ermittelt MySQL anhand des Modulus des Ergebnisses der
Benutzerfunktion, welche von num
Partitionen verwendet wird. Anders ausgedrückt: Für einen
Ausdruck expr
wird der Datensatz in
der Partition N
gespeichert, wobei
ist. Nehmen wir
beispielsweise an, Tabelle N
=
MOD(expr
,
num
)t1
ist
folgendermaßen definiert, sodass sie 4 Partitionen hat:
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY HASH( YEAR(col3) ) PARTITIONS 4;
Wenn Sie in t1
einen Datensatz einfügen,
dessen col3
-Wert
'2005-09-15'
ist, dann wird die Partition, in
der er gespeichert wird, folgendermaßen ermittelt:
MOD(YEAR('2005-09-01'),4) = MOD(2005,4) = 1
MySQL 5.1 unterstützt auch eine Variante der
HASH
-Partitionierung namens
lineares Hashing, die einen komplexen
Algorithmus einsetzt, um neu in eine partitionierte Tabelle
eingefügte Zeilen zu platzieren. Eine Beschreibung dieses
Algorithmus finden Sie unter
Abschnitt 17.2.3.1, „LINEAR HASH
-Partitionierung“.
Die Benutzerfunktion wird bei jeder Einfügung oder Aktualisierung und unter Umständen auch bei einer Löschung eines Datensatzes ausgewertet.
Hinweis: Wenn die Tabelle, die
partitioniert werden soll, einen
UNIQUE
-Schlüssel hat, müssen Spalten, die
als Argumente an die HASH
-Benutzerfunktion
oder die column_list
des
KEY
s übergeben werden, Teil dieses
Schlüssels sein.
MySQL unterstützt auch lineares Hashing, das sich vom regulären Hashing insofern unterscheidet, als es einen linearen Zweierpotenz-Algorithmus verwendet, während das reguläre Hashing den Modulus des Werts der Hashing-Funktion benutzt.
Der einzige syntaktische Unterschied zwischen der linearen und
der regulären Hash-Partitionierung besteht darin, dass der
PARTITION BY
-Klausel das Schlüsselwort
LINEAR
hinzugefügt wird:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31', job_code INT, store_id INT ) PARTITION BY LINEAR HASH( YEAR(hired) ) PARTITIONS 4;
Wenn Sie einen Ausdruck expr
haben,
wird beim linearen Hashing der Datensatz in Partition Nummer
N
von
num
Partitionen gespeichert, wobei
N
nach dem folgenden Algorithmus
abgeleitet ist:
Finde die nächste Zweierpotenz größer
num
. Wir nennen diesen Wert
V
; er kann folgendermaßen
berechnet werden:
V
= POWER(2, CEILING(LOG(2,num
)))
(Nehmen wir beispielsweise an,
num
sei 13. Dann ist
LOG(2,13)
gleich 3.7004397181411.
CEILING(3.7004397181411)
ist 4 und
V
=
POWER(2,4)
, was 16 ergibt.)
Setze N
=
F
(column_list
)
& (V
- 1).
Wobei N
>=
num
:
Setze V
=
CEIL(V
/ 2)
Setze N
=
N
&
(V
- 1)
Angenommen, die Tabelle t1
, die lineare
Hash-Partitionierung nutzt und 6 Partitionen hat, wird mit
folgender Anweisung angelegt:
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY LINEAR HASH( YEAR(col3) ) PARTITIONS 6;
Nehmen wir weiterhin an, Sie möchten in t1
zwei Datensätze einfügen, in denen die Spalte
col3
die Werte
'2003-04-14'
und
'1998-10-19'
aufweist. Die Partitionsnummer
für die erste dieser Spalten wird folgendermaßen ermittelt:
V
= POWER(2, CEILING( LOG(2,7) )) = 8N
= YEAR('2003-04-14') & (8 - 1) = 2003 & 7 = 3 (3 >= 6 is FALSE: record stored in partition #3)
Die Partitionsnummer für den zweiten Eintrag wird berechnet mit:
V
= 8N
= YEAR('1998-10-19') & (8-1) = 1998 & 7 = 6 (6 >= 6 is TRUE: additional step required)N
= 6 & CEILING(5 / 2) = 6 & 3 = 2 (2 >= 6 is FALSE: record stored in partition #2)
Der Vorteil einer linearen Hash-Partitionierung besteht darin, dass sich Partitionen weit schneller hinzufügen, löschen, zusammenführen und aufspalten lassen. Das kann ein Segen sein, wenn man mit Tabellen arbeiten muss, die extrem große Datenmengen (Terabytes) enthalten. Der Nachteil ist, dass die Daten wahrscheinlich nicht so gleichmäßig auf die Partitionen verteilt werden wie bei der normalen Hash-Partitionierung.
Die Partitionierung durch Schlüssel gleicht der Partitionierung
durch Hash, nur dass dort, wo die Hash-Partitionierung einen
benutzerdefinierten Ausdruck verwendet, die
Schlüsselpartitionierung eine vom MySQL Server gelieferte
Hash-Funktion einsetzt. MySQL Cluster verwendet zu diesem Zweck
MD5()
; für Tabellen, die andere
Speicher-Engines benutzen, setzt der Server seine eigene interne
Hash-Funktion ein, die auf demselben Algorithmus wie
PASSWORD()
beruht.
Die Syntaxregeln für CREATE TABLE ... PARTITION BY
KEY
sind dieselben wie bei der Erstellung einer
Hash-partitionierten Tabelle. Die Hauptunterschiede sind:
Statt HASH
wird KEY
eingesetzt.
KEY
nimmt nur eine Liste mit einem oder
mehreren Spaltennamen entgegen. Seit MySQL 5.1.5 müssen die
Spalten, die als Partitionierungsschlüssel eingesetzt
werden, den Primärschlüssel der Tabelle (sofern sie einen
hat) ganz oder teilweise abdecken.
Seit MySQL 5.1.6 nimmt KEY
eine Liste mit
null oder mehr Spaltennamen entgegen. Wenn kein Spaltenname
als Partitionierungsschlüssel angegeben ist, wird der
Primärschlüssel der Tabelle verwendet. Die folgende
CREATE TABLE
-Anweisung gilt
beispielsweise in MySQL 5.1.6 oder höher:
CREATE TABLE k1 ( id INT NOT NULL PRIMARY KEY, name VARCHAR(20) ) PARTITION BY KEY() PARTITIONS 2;
In diesem Fall ist der Partitionierungsschlüssel die Spalte
id
, auch wenn das in der Ausgabe von
SHOW CREATE TABLE
oder in der Spalte
PARTITION_EXPRESSION
der Tabelle
INFORMATION_SCHEMA.PARTITIONS
nicht
erkennbar ist.
Hinweis: Seit MySQL 5.1.6
werden außerdem Tabellen, die die Speicher-Engine
NDB Cluster
verwenden, implizit mit
KEY
partitioniert, wobei auch hier wieder
der Primärschlüssel der Tabelle als
Partitionierungsschlüssel dient. Nehmen wir als Beispiel
die Tabelle, die mit folgender Anweisung erzeugt wird:
CREATE TABLE kndb ( id INT NOT NULL PRIMARY KEY, name VARCHAR(20) NOT NULL ) ENGINE=NDBCLUSTER;
Obwohl die Anweisung keine PARTITION
BY
-Klausel enthält, zeigt die Ausgabe von
SHOW CREATE TABLE kndb
Folgendes an:
CREATE TABLE `kndb` ( `id` int(11) NOT NULL, `name` varchar(20) NOT NULL. PRIMARY KEY (`id`) ) ENGINE=ndbcluster DEFAULT CHARSET=latin1 PARTITION BY KEY ();
Falls die Cluster-Tabelle keinen expliziten
Primärschlüssel hat, wird der „verborgene“
Primärschlüssel, den die Speicher-Engine
NDB
automatisch für jede Cluster-Tabelle
generiert, als Partitionierungsschlüssel eingesetzt.
Wichtig: Auf einer
schlüsselpartitionierten Tabelle, die eine andere
Speicher-Engine als NDB CLuster
verwendet, können Sie keine ALTER TABLE DROP
PRIMARY KEY
-Anweisung ausführen, ansonsten tritt
der Fehler ERROR 1466 (HY000): Field in list of
fields for partition function not found in table
ein. Dieses Problem betrifft keine MySQL CLuster-Tabellen,
die durch KEY
partitioniert werden: In
solchen Fällen wird die Tabelle reorganisiert, wobei der
„verborgene“ Primärschlüssel als neuer
Partitionierungsschlüssel der Tabelle verwendet wird. Siehe
Kapitel 16, MySQL Cluster.
Es ist auch möglich, eine Tabelle durch linearen Schlüssel zu partitionieren. Hier sehen Sie ein einfaches Beispiel:
CREATE TABLE tk ( col1 INT NOT NULL, col2 CHAR(5), col3 DATE ) PARTITION BY LINEAR KEY (col1) PARTITIONS 3;
Die Verwendung von LINEAR
hat auf die
KEY
-Partitionierung denselben Effekt wie auf
die HASH
-Partitionierung, wobei die
Partitionsnummer mit einem Zweierpotenz-Algorithmus anstatt mit
Modulo-Arithmetik abgeleitet wird. Eine Beschreibung dieses
Algorithmus und seiner Implikationen finden Sie unter
Abschnitt 17.2.3.1, „LINEAR HASH
-Partitionierung“.
Teilpartitionierung, auch als zusammengesetzte
Partitionierung bezeichnet, ist die weitere
Unterteilung von Partitionen einer partitionierten Tabelle.
Betrachten Sie als Beispiel die folgende CREATE
TABLE
-Anweisung:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE(YEAR(purchased)) SUBPARTITION BY HASH(TO_DAYS(purchased)) SUBPARTITIONS 2 ( PARTITION p0 VALUES LESS THAN (1990), PARTITION p1 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN MAXVALUE );
Die Tabelle ts
hat 3
RANGE
-Partitionen. Jede dieser Partitionen,
also p0
, p1
und
p2
, ist ihrerseits in 2 Teilpartitionen
unterteilt. Im Endeffekt ist die gesamte Tabelle auf 3
* 2 = 6
Partitionen verteilt. Durch die
PARTITION BY RANGE
-Klausel speichern
allerdings die ersten beiden dieser Partitionen nur Datensätze,
die in der purchased
-Spalte einen Wert
kleiner als 1990 aufweisen.
In MySQL 5.1 können Sie Tabellen, die durch
RANGE
oder LIST
partitioniert werden, noch weiter aufteilen. Teilpartitionen
können entweder die HASH
- oder die
KEY
-Partitionierung verwenden. Dies
bezeichnet man auch als zusammengesetzte
Partitionierung.
Außerdem ist es möglich, Teilpartitionen explizit mit
SUBPARTITION
-Klauseln zu definieren, um
Optionen für einzelne Teilpartitionen angeben zu können. So
könnte man dieselbe ts
-Tabelle wie im
vorigen Beispiel auch wortreicher erzeugen:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0, SUBPARTITION s1 ), PARTITION p1 VALUES LESS THAN (2000) ( SUBPARTITION s2, SUBPARTITION s3 ), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s4, SUBPARTITION s5 ) );
An dieser Syntax ist Folgendes bemerkenswert:
Jede Partition muss dieselbe Anzahl Teilpartitionen haben.
Wenn Sie mit SUBPARTITION
explizit
Teilpartitionen für eine Partition einer partitionierten
Tabelle definieren, müssen Sie sie für alle anderen auch
definieren. Die folgende Anweisung wird scheitern:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0, SUBPARTITION s1 ), PARTITION p1 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s2, SUBPARTITION s3 ) );
Die Anweisung würde sogar dann fehlschlagen, wenn sie eine
SUBPARTITIONS 2
-Klausel enthielte.
Jede SUBPARTITION
-Klausel muss
(mindestens) den Namen für die Teilpartition enthalten.
Ansonsten können Sie alle Optionen setzen, die Sie
wünschen, oder aber die Teilpartition mit den
Standardeinstellungen anlegen.
Teilpartitionsnamen müssen innerhalb einer Partition
eindeutig sein, aber nicht innerhalb der Tabelle als Ganzes.
So ist beispielsweise die folgende CREATE
TABLE
-Anweisung zulässig:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0, SUBPARTITION s1 ), PARTITION p1 VALUES LESS THAN (2000) ( SUBPARTITION s0, SUBPARTITION s1 ), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s0, SUBPARTITION s1 ) );
Teilpartitionen können bei extrem großen Tabellen helfen, die
Daten und Indizes über viele Festplatten zu verteilen.
Angenommen, Sie haben 6 Festplatten als
/disk0
, /disk1
,
/disk2
und so weiter gemountet. Nun schauen
Sie sich folgendes Beispiel an:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0 DATA DIRECTORY = '/disk0/data' INDEX DIRECTORY = '/disk0/idx', SUBPARTITION s1 DATA DIRECTORY = '/disk1/data' INDEX DIRECTORY = '/disk1/idx' ), PARTITION p1 VALUES LESS THAN (2000) ( SUBPARTITION s0 DATA DIRECTORY = '/disk2/data' INDEX DIRECTORY = '/disk2/idx', SUBPARTITION s1 DATA DIRECTORY = '/disk3/data' INDEX DIRECTORY = '/disk3/idx' ), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s0 DATA DIRECTORY = '/disk4/data' INDEX DIRECTORY = '/disk4/idx', SUBPARTITION s1 DATA DIRECTORY = '/disk5/data' INDEX DIRECTORY = '/disk5/idx' ) );
In diesem Fall wird für die Daten und die Indizes jedes
RANGE
eine eigene Festplatte genutzt. Es sind
aber auch viele andere Varianten möglich; ein anderes Beispiel
wäre:
CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE(YEAR(purchased)) SUBPARTITION BY HASH(TO_DAYS(purchased)) ( PARTITION p0 VALUES LESS THAN (1990) ( SUBPARTITION s0a DATA DIRECTORY = '/disk0' INDEX DIRECTORY = '/disk1', SUBPARTITION s0b DATA DIRECTORY = '/disk2' INDEX DIRECTORY = '/disk3' ), PARTITION p1 VALUES LESS THAN (2000) ( SUBPARTITION s1a DATA DIRECTORY = '/disk4/data' INDEX DIRECTORY = '/disk4/idx', SUBPARTITION s1b DATA DIRECTORY = '/disk5/data' INDEX DIRECTORY = '/disk5/idx' ), PARTITION p2 VALUES LESS THAN MAXVALUE ( SUBPARTITION s2a, SUBPARTITION s2b ) );
Hier wird nach folgenden Regeln gespeichert:
Da Zeilen mit purchased
-Daten aus der
Zeit vor 1990 sehr viel Platz belegen, werden sie auf vier
Arten aufgeteilt, wobei jeweils eine eigene Festplatte den
Daten und Indizes jeder der beiden Teilpartitionen
(s0a
und s0b
) der
Partition p0
gewidmet ist. Mit anderen
Worten:
Die Daten für die Teilpartition s0a
werden auf /disk0
gespeichert.
Die Indizes für die Teilpartition
s0a
werden auf
/disk1
gespeichert.
Die Daten für die Teilpartition s0b
werden auf /disk2
gespeichert.
Die Indizes für die Teilpartition
s0b
werden auf
/disk3
gespeichert.
Die Zeilen mit den Daten der Jahre 1990 bis 1999 (Partition
p1
) belegen nicht so viel Speicher wie
die Daten von vor 1990. So werden sie auf zwei Festplatten
(/disk4
und
/disk5
) verteilt, nicht auf vier, wie
wir es mit den alten in p0
gespeicherten
Daten getan haben:
Die Daten und Indizes der ersten Teilpartition von
p1
(s1a
) werden
auf /disk4
gespeichert, und zwar
die Daten im Verzeichnis
/disk4/data
und die Indizes im
Verzeichnis /disk4/idx
.
Die Daten und Indizes der zweiten Teilpartition von
p1
(s1b
) werden
auf /disk5
gespeichert, und zwar
die Daten im Verzeichnis
/disk5/data
und die Indizes im
Verzeichnis /disk5/idx
.
Die Zeilen der Daten, die die Jahre ab 2000 betreffen
(Partition p2
), nehmen noch weniger
Speicherplatz in Anspruch als die beiden anderen
Datumsbereiche. Zurzeit reicht der Standardspeicherort noch
für sie aus.
Wenn später einmal die Verkaufsdaten für die mit dem Jahr
2000 beginnende Dekade so umfangreich werden, dass der
Standardspeicherort nicht mehr ausreicht, können die
entsprechenden Zeilen mit einer ALTER TABLE ...
REORGANIZE PARTITION
-Anweisung verschoben werden.
Wie das geht, erfahren Sie unter
Abschnitt 17.3, „Partitionsverwaltung“.
Die Partitionierung in MySQL gestattet durchaus auch einen
Partitionierungsausdruck mit dem Wert NULL
,
sei es nun ein Spaltenwert oder der Wert eines vom Benutzer
angegebenen Ausdrucks. Normalerweise behandelt MySQL
NULL
in solchen Fällen als null. Wenn Sie
dieses Verhalten unterbinden möchten, müssen Sie Tabellen so
entwerfen, dass sie keine Nullwerte erlauben, indem Sie die
Spalten als NOT NULL
deklarieren.
In diesem Abschnitt geben wir einige Beispiele, die zeigen
sollen, wie MySQL NULL
-Werte verarbeitet,
wenn die passende Partition für eine Zeile ermittelt werden
soll.
Wenn Sie eine Zeile in eine RANGE
- oder
LIST
-partitionierte Tabelle einfügen und der
Spaltenwert, der zur Bestimmung der Partition herangezogen wird,
NULL
ist, so wird dieser Wert als
0
interpretiert. Betrachten Sie
beispielsweise die folgenden beiden Tabellen:
mysql>CREATE TABLE tnlist (
->id INT,
->name VARCHAR(5)
->)
->PARTITION BY LIST(id) (
->PARTITION p1 VALUES IN (0),
->PARTITION p2 VALUES IN (1)
->);
Query OK, 0 rows affected (0.09 sec) mysql>CREATE TABLE tnrange (
->id INT,
->name VARCHAR(5)
->)
->PARTITION BY RANGE(id) (
->PARTITION p1 VALUES LESS THAN (1),
->PARTITION p2 VALUES LESS THAN MAXVALUE
->);
Query OK, 0 rows affected (0.09 sec) mysql>INSERT INTO tnlist VALUES (NULL, 'bob');
Query OK, 1 row affected (0.00 sec) mysql>INSERT INTO tnrange VALUES (NULL, 'jim');
Query OK, 1 row affected (0.00 sec) mysql>SELECT * FROM tnlist;
+------+------+ | id | name | +------+------+ | NULL | bob | +------+------+ 1 row in set (0.00 sec) mysql>SELECT * FROM tnrange;
+------+------+ | id | name | +------+------+ | NULL | jim | +------+------+ 1 row in set (0.00 sec)
In beiden Tabellen war die Spalte id
nicht
als NOT NULL
deklariert, kann also
NULL
-Werte annehmen. Dass die Zeilen in den
p1
-Partitionen der Tabellen gespeichert
wurden, können Sie überprüfen, indem Sie diese Partitionen
löschen und dann die SELECT
-Anweisungen
erneut ausführen:
mysql>ALTER TABLE tnlist DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec) mysql>ALTER TABLE tnrange DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec) mysql>SELECT * FROM tnlist;
Empty set (0.00 sec) mysql>SELECT * FROM tnrange;
Empty set (0.00 sec)
Bei einer HASH
- oder
KEY
-Partitionierung wird ein
Partitionierungsausdruck, der NULL
ergibt, so
behandelt, als sei sein Rückgabewert null. Dieses Verhalten
können wir überprüfen, indem wir betrachten, wie sich die
Erstellung einer HASH
-partitionierten
Tabelle, in die eine Zeile mit den entsprechenden Daten geladen
wird, auf das Dateisystem auswirkt. Angenommen, Sie haben eine
Tabelle namens tnhash
in der Datenbank
test
mit folgender Anweisung angelegt:
CREATE TABLE tnhash ( id INT, name VARCHAR(5) ) PARTITION BY HASH(id) PARTITIONS 2;
Wenn wir eine RPM-Installation von MySQL auf Linux zugrunde
legen, erzeugt diese Anweisung zwei
.MYD
-Dateien in
/var/lib/mysql/test
, die in der
bash-Shell wie folgt angezeigt werden
können:
/var/lib/mysql/test> ls *.MYD -l
-rw-rw---- 1 mysql mysql 0 2005-11-04 18:41 tnhash#P#p0.MYD
-rw-rw---- 1 mysql mysql 0 2005-11-04 18:41 tnhash#P#p1.MYD
(Hinweis: Vor MySQL 5.1.5
hätten diese Dateien tnhash_p0.MYD
und
tnhash_p1.MYD
geheißen. Unter
Abschnitt D.1.1, „Änderungen in Release 5.1.6 (Noch nicht veröffentlicht)“, und Bug#13437 finden Sie weitere
Informationen darüber, wie sich diese Änderung auf Upgrades
auswirkt.)
Beachten Sie, dass die beiden Dateien 0 Byte groß sind. Fügen
Sie nun in tnhash
eine Zeile ein, die in der
Spalte id
den Wert NULL
aufweist, und überprüfen Sie, ob die Zeile tatsächlich
eingefügt wurde:
mysql>INSERT INTO tnhash VALUES (NULL, 'sam');
Query OK, 1 row affected (0.00 sec) mysql>SELECT * FROM tnhash;
+------+------+ | id | name | +------+------+ | NULL | sam | +------+------+ 1 row in set (0.01 sec)
Bitte erinnern Sie sich, dass für einen Integer
N
der Wert von NULL MOD
immer
N
NULL
ist. Dieses Ergebnis wird behandelt, um
0
als die korrekte Partition festzulegen.
Wenn wir nun wieder in die System-Shell gehen (wobei weiterhin
bash zugrunde gelegt wird), können wir
erkennen, dass der Wert in die erste Partition (die nach
Voreinstellung p0
heißt) eingefügt wurde,
indem wir die Datendateien erneut auflisten:
var/lib/mysql/test> ls *.MYD -l
-rw-rw---- 1 mysql mysql 20 2005-11-04 18:44 tnhash#P#p0.MYD
-rw-rw---- 1 mysql mysql 0 2005-11-04 18:41 tnhash#P#p1.MYD
Wie Sie sehen, hat die INSERT
-Anweisung nur
die Datei tnhash_p0.MYD
modifiziert, deren
Umfang auf der Platte angewachsen ist, ohne auf die andere
Datendatei Einfluss zu nehmen.
Nehmen wir nun an, wir hätten folgende Tabelle:
CREATE TABLE tndate ( id INT, dt DATE ) PARTITION BY RANGE( YEAR(dt) ) ( PARTITION p0 VALUES LESS THAN (1990), PARTITION p1 VALUES LESS THAN (2000), PARTITION p2 VALUES LESS THAN MAXVALUE );
Wie andere MySQL-Funktionen gibt auch
YEAR(NULL)
den Wert NULL
zurück. Eine Zeile, die in der dt
-Spalte den
Wert NULL
hat, wird behandelt, als wäre der
Partitionierungsausdruck in Wirklichkeit 0
,
und folglich in die Partition p0
eingefügt.
MySQL 5.1 bietet eine Reihe von Möglichkeiten, um
partitionierte Tabellen zu modifizieren. Man kann Partitionen
hinzufügen, löschen, umdefinieren, zusammenführen oder
aufspalten. Alle diese Aktionen werden mit den
Partitionierungserweiterungen des ALTER
TABLE
-Befehls ausgeführt (zur Syntax siehe
Abschnitt 13.1.2, „ALTER TABLE
“). Darüber hinaus können Sie sich
Informationen über partitionierte Tabellen und Partitionen
beschaffen. Diese Themen werden in den nachfolgenden Abschnitten
behandelt.
Informationen über die Partitionsverwaltung in
RANGE
- oder
LIST
-partitionierten Tabellen finden Sie
unter Abschnitt 17.3.1, „Verwaltung von RANGE
- und
LIST
-Partitionen“.
Um die Verwaltung von HASH
- und
KEY
-Partitionen geht es in
Abschnitt 17.3.2, „Verwaltung von HASH
- und
KEY
-Partitionen“.
Mechanismen, mit denen Sie in MySQL 5.1 Informationen über partitionierte Tabellen and Partitionen erlangen können, werden in Abschnitt 17.3.4, „Abruf von Informationen über Partitionen“, vorgestellt.
Wartungsoperationen auf Partitionen werden in Abschnitt 17.3.3, „Wartung von Partitionen“, beschrieben.
Hinweis: In MySQL 5.1 müssen alle Partitionen einer partitionierten Tabelle die gleiche Anzahl von Teilpartitionen haben. Nach dem Anlegen der Tabelle ist es nicht mehr möglich, die Teilpartitionierung zu ändern.
Die Anweisung ALTER TABLE ... PARTITION BY ...
funktioniert seit MySQL 5.1.6; zuvor in MySQL 5.1 wurde ihre
Syntax zwar als gültig akzeptiert, aber Auswirkungen hatte sie
keine.
Um das Partitionierungsschema einer Tabelle zu ändern, müssen
Sie nur dem ALTER TABLE
-Befehl eine
partition_options
-Klausel hinzufügen.
Diese Klausel hat dieselbe Syntax, die auch in CREATE
TABLE
zur Erstellung einer partitionierten Tabelle
verwendet wird, und beginnt immer mit den Schlüsselwörtern
PARTITION BY
. Angenommen, Sie haben eine nach
Bereichen partitionierte Tabelle mit folgender CREATE
TABLE
-Anweisung angelegt:
CREATE TABLE trb3 (id INT, name VARCHAR(50), purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990), PARTITION p1 VALUES LESS THAN (1995), PARTITION p2 VALUES LESS THAN (2000), PARTITION p3 VALUES LESS THAN (2005) );
Um aus dieser Tabelle eine schlüsselpartitionierte Tabelle mit
zwei Partitionen zu machen, wobei der Wert der Spalte
id
die Grundlage für den Schlüssel liefert,
können Sie folgende Anweisung geben:
ALTER TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;
Auf die Struktur der Tabelle hat dies dieselben Auswirkungen wie
eine Löschung und Rekonstruktion mit CREATE TABLE trb3
PARTITION BY KEY(id) PARTITIONS 2;
.
Da das Hinzufügen und Löschen von Partitionen für Bereichs-
und Listenpartitionen ganz ähnlich behandelt wird, fassen wir
die Verwaltung dieser beiden Partitionierungsarten im
vorliegenden Abschnitt zusammen. Über den Umgang mit Hash- oder
schlüsselpartitionierten Tabellen erfahren Sie unter
Abschnitt 17.3.2, „Verwaltung von HASH
- und
KEY
-Partitionen“, Genaueres.
Weil das Löschen einer RANGE
- oder
LIST
--Partition einfacher ist als das
Hinzufügen, beginnen wir mit dem Löschen.
Um eine Partition aus einer RANGE
- oder
LIST
-partitionierten Tabelle zu löschen,
verwenden Sie den ALTER TABLE
-Befehl mit
einer DROP PARTITION
-Klausel. Das folgende
sehr einfach gehaltene Beispiel geht davon aus, dass Sie mit den
folgenden CREATE TABLE
- und
INSERT
-Anweisungen bereits eine nach Bereich
partitionierte Tabelle angelegt und mit 10 Datensätzen
bevölkert haben:
mysql>CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)
->PARTITION BY RANGE( YEAR(purchased) ) (
->PARTITION p0 VALUES LESS THAN (1990),
->PARTITION p1 VALUES LESS THAN (1995),
->PARTITION p2 VALUES LESS THAN (2000),
->PARTITION p3 VALUES LESS THAN (2005)
->);
Query OK, 0 rows affected (0.01 sec) mysql>INSERT INTO tr VALUES
->(1, 'desk organiser', '2003-10-15'),
->(2, 'CD player', '1993-11-05'),
->(3, 'TV set', '1996-03-10'),
->(4, 'bookcase', '1982-01-10'),
->(5, 'exercise bike', '2004-05-09'),
->(6, 'sofa', '1987-06-05'),
->(7, 'popcorn maker', '2001-11-22'),
->(8, 'aquarium', '1992-08-04'),
->(9, 'study desk', '1984-09-16'),
->(10, 'lava lamp', '1998-12-25');
Query OK, 10 rows affected (0.01 sec)
Welche Daten in die Partition p2
geladen
wurden, sehen Sie hier:
mysql>SELECT * FROM tr
->WHERE purchased BETWEEN '1995-01-01' AND '1999-12-31';
+------+-----------+------------+ | id | name | purchased | +------+-----------+------------+ | 3 | TV set | 1996-03-10 | | 10 | lava lamp | 1998-12-25 | +------+-----------+------------+ 2 rows in set (0.00 sec)
Um nun die Partition p2
zu löschen, führen
Sie folgenden Befehl aus:
mysql> ALTER TABLE tr DROP PARTITION p2;
Query OK, 0 rows affected (0.03 sec)
Hinweis: Die Speicher-Engine NDB Cluster
in
MySQL 5.1 kennt kein ALTER TABLE ... DROP
PARTITION
. Doch immerhin unterstützt sie die anderen
in diesem Kapitel beschriebenen Partitionierungserweiterungen
der ALTER TABLE
-Anweisung.
Es ist sehr wichtig, sich zu merken, dass Sie beim
Löschen einer Partition alle darin gespeicherten Daten mit
löschen. Dies erkennen Sie, wenn Sie die obige
SELECT
-Anfrage erneut ausführen:
mysql>SELECT * FROM tr WHERE purchased
->BETWEEN '1995-01-01' AND '1999-12-31';
Empty set (0.00 sec)
Wenn Sie alle Daten aus allen Partitionen löschen, aber die
Tabellendefinition und ihr Partitionierungsschema erhalten
möchten, verwenden Sie den Befehl TRUNCATE
TABLE
. (Siehe auch Abschnitt 13.2.9, „TRUNCATE
“.)
Wenn Sie die Partitionierung einer Tabelle ändern möchten,
ohne Daten zu verlieren, verwenden Sie
stattdessen ALTER TABLE ... REORGANIZE
PARTITION
. Weiter unten oder in
Abschnitt 13.1.2, „ALTER TABLE
“, finden Sie Informationen über
REORGANIZE PARTITION
.
Wenn Sie nun einen SHOW CREATE TABLE
-Befehl
ausführen, können Sie sehen, wie sich die Partitionierung der
Tabelle geändert hat:
mysql> SHOW CREATE TABLE tr\G
*************************** 1. row ***************************
Table: tr
Create Table: CREATE TABLE `tr` (
`id` int(11) default NULL,
`name` varchar(50) default NULL,
`purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE ( YEAR(purchased) ) (
PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM,
PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.01 sec)
Wenn Sie nun in die geänderte Tabelle Zeilen einfügen, die in
der Spalte purchased
Werte zwischen
'1995-01-01'
und
'2004-12-31'
einschließlich aufweisen,
werden diese Zeilen in der Partition p3
gespeichert. Dies können Sie folgendermaßen überprüfen:
mysql>INSERT INTO tr VALUES (11, 'pencil holder', '1995-07-12');
Query OK, 1 row affected (0.00 sec) mysql>SELECT * FROM tr WHERE purchased
->BETWEEN '1995-01-01' AND '2004-12-31';
+------+----------------+------------+ | id | name | purchased | +------+----------------+------------+ | 11 | pencil holder | 1995-07-12 | | 1 | desk organiser | 2003-10-15 | | 5 | exercise bike | 2004-05-09 | | 7 | popcorn maker | 2001-11-22 | +------+----------------+------------+ 4 rows in set (0.00 sec) mysql>ALTER TABLE tr DROP PARTITION p3;
Query OK, 0 rows affected (0.03 sec) mysql>SELECT * FROM tr WHERE purchased
->BETWEEN '1995-01-01' AND '2004-12-31';
Empty set (0.00 sec)
Beachten Sie, dass die Anzahl der Zeilen, die aus der Tabelle
mit ALTER TABLE ... DROP PARTITION
gelöscht
wurden, vom Server nicht so gemeldet wird, wie es bei einer
entsprechenden DELETE
-Anweisung der Fall
wäre.
Zum Löschen von LIST
-Partitionen wird genau
dieselbe ALTER TABLE ... DROP
PARTITION
-Syntax verwendet wie zum Löschen von
RANGE
-Partitionen. Allerdings unterscheiden
sich die Auswirkungen, die dieses auf den späteren Gebrauch der
Tabelle hat, in einer wichtigen Hinsicht: In die Tabelle können
nun keine Zeilen mehr eingefügt werden, die irgendwelche in der
Werteliste der gelöschten Partition vorkommenden Werte
aufweisen. (Ein Beispiel finden Sie unter
Abschnitt 17.2.2, „LIST
-Partitionierung“.)
Um einer zuvor partitionierten Tabelle eine neue Bereichs- oder
Listenpartition hinzuzufügen, verwenden Sie die ALTER
TABLE ... ADD PARTITION
-Anweisung. Für Tabellen, die
nach RANGE
partitioniert werden, können Sie
mit dieser Anweisung einen neuen Wertebereich am Anfang oder
Ende der Liste der vorhandenen Partitionen hinzufügen.
Angenommen, Sie haben eine partitionierte Tabelle mit
Mitgliedsdaten Ihrer Organisation wie folgt definiert:
CREATE TABLE members ( id INT, fname VARCHAR(25), lname VARCHAR(25), dob DATE ) PARTITION BY RANGE( YEAR(dob) ) ( PARTITION p0 VALUES LESS THAN (1970), PARTITION p1 VALUES LESS THAN (1980), PARTITION p2 VALUES LESS THAN (1990) );
Nehmen wir nun weiterhin an, das Mindestalter der Mitglieder ist
16 Jahre. Da es bereits auf Ende 2005 zugeht, stellen Sie fest,
dass Sie demnächst Mitglieder aufnehmen müssen, die 1990
geboren wurden, und in den darauf folgenden Jahren wiederum
Mitglieder, die noch später zur Welt kamen. Mit folgender
Anweisung können Sie die members
-Tabelle so
umändern, dass auch Mitglieder zulässig sind, die in den
Jahren 1990 bis 1999 geboren wurden:
ALTER TABLE ADD PARTITION (PARTITION p3 VALUES LESS THAN (2000));
Wichtig: Tabellen, die nach
Bereich partitioniert wurden, können Sie mit dem Befehl
ADD PARTITION
nur am oberen Ende der
Wertebereichsliste neue Partitionen hinzufügen. Wenn Sie
versuchen, auf diesem Weg Partitionen zwischen oder vor
vorhandenen Partitionen einzufügen, wird folgender Fehler
generiert:
mysql>ALTER TABLE members
>ADD PARTITION (
>PARTITION p3 VALUES LESS THAN (1960));
ERROR 1463 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
In ähnlicher Weise können Sie auch einer
LIST
-partitionierten Tabelle neue Partitionen
hinzufügen. Nehmen wir als Beispiel folgende Tabelle:
CREATE TABLE tt ( id INT, data INT ) PARTITION BY LIST(data) ( PARTITION p0 VALUES IN (5, 10, 15), PARTITION p1 VALUES IN (6, 12, 18) );
Mit der folgenden Anweisung können Sie eine neue Partition für
Zeilen einrichten, deren data
-Spalten die
Werte 7
, 14
und
21
aufweisen:
ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21));
Achtung: Sie können keine neue
LIST
-Partition hinzufügen, die irgendwelche
bereits in den Wertelisten bestehender Partitionen enthaltenen
Werte aufweist. Wenn Sie dieses versuchen, wird ein Fehler
gemeldet:
mysql>ALTER TABLE tt ADD PARTITION
>(PARTITION np VALUES IN (4, 8, 12));
ERROR 1465 (HY000): Multiple definition of same constant in list partitioning
Da Zeilen mit dem Wert 12
in der
data
-Spalte bereits der Partition
p1
zugewiesen sind, können Sie nicht in
Tabelle tt
eine neue Partition anlegen, die
ebenfalls 12
in ihrer Werteliste hat. Wenn
Sie dies dennoch tun müssen, löschen Sie zuerst
p1
und fügen dann np
und
danach eine neue p1
mit einer modifizierten
Definition hinzu. Allerdings würden dadurch, wie zuvor bereits
gesagt, alle in p1
gespeicherten Daten
verloren gehen, was im Allgemeinen nicht der angestrebte Effekt
ist. Eine andere Lösung könnte so aussehen, dass Sie eine
Kopie der Tabelle mit der neuen Partitionierung anlegen, dann
die Daten mit einer CREATE TABLE ... SELECT
...
hineinkopieren und schließlich die alte Tabelle
löschen und die neue umbenennen. Wenn Sie es mit großen
Datenmengen zu tun haben, könnte dies allerdings eine
zeitraubende Angelegenheit werden, die dort, wo
Hochverfügbarkeit gewährleistet werden muss, vielleicht
vollends unmöglich ist.
Seit MySQL 5.1.6 können Sie mehrere Partitionen in einer
einzigen ALTER TABLE ... ADD
PARTITION
-Anweisung anlegen:
CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL, hired DATE NOT NULL ) PARTITION BY RANGE( YEAR(hired) ) ( PARTITION p1 VALUES LESS THAN (1991), PARTITION p2 VALUES LESS THAN (1996), PARTITION p3 VALUES LESS THAN (2001), PARTITION p4 VALUES LESS THAN (2005) ); ALTER TABLE employees ADD PARTITION ( PARTITION p5 VALUES LESS THAN (2010), PARTITION p6 VALUES LESS THAN MAXVALUE );
Zum Glück bietet die Implementierung der Partitionierung in
MySQL Möglichkeiten, Partitionen ohne Datenverlust
umzudefinieren. Betrachten wir zunächst eine Reihe von
einfachen Beispielen zur
RANGE
-Partitionierung. Bitte erinnern Sie
sich an die members
-Tabelle, die nun
folgendermaßen definiert ist:
mysql> SHOW CREATE TABLE members\G
*************************** 1. row ***************************
Table: members
Create Table: CREATE TABLE `members` (
`id` int(11) default NULL,
`fname` varchar(25) default NULL,
`lname` varchar(25) default NULL,
`dob` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE ( YEAR(dob) ) (
PARTITION p0 VALUES LESS THAN (1970) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (1980) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (1990) ENGINE = MyISAM.
PARTITION p3 VALUES LESS THAN (2000) ENGINE = MyISAM
)
Angenommen, Sie möchten alle Zeilen der Mitglieder, die vor
1960 geboren wurden, in eine separate Partition speichern. Wir
wir bereits sahen, ist dies mit der Anweisung ALTER
TABLE ... ADD PARTITION
nicht möglich. Sie können
jedoch eine andere Partitionierungserweiterung von
ALTER TABLE
benutzen, um dies zu erreichen:
ALTER TABLE members REORGANIZE PARTITION p0 INTO ( PARTITION s0 VALUES LESS THAN (1960), PARTITION s1 VALUES LESS THAN (1970) );
Im Endeffekt spaltet dieser Befehl die Partition
p0
in zwei neue Partitionen
s0
und s1
auf. Außerdem
werden die bisher in p0
gespeicherten Daten
nach den Regeln der beiden PARTITION ... VALUES
...
-Klauseln auf die neuen Partitionen verteilt,
sodass s0
nur Datensätze aufnimmt, deren
YEAR(dob)
-Wert kleiner als 1960 ist, und
s1
nur Datensätze, deren
YEAR(dob)
-Wert größer oder gleich 1960,
aber kleiner als 1970 ist.
Sie können auch mit einer REORGANIZE
PARTITION
-Klausel benachbartete Partitionen
verschmelzen. Mit dem folgenden Befehl stellen Sie die
members
-Tabelle wieder auf ihre vorherige
Partitionierung um:
ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO ( PARTITION p0 VALUES LESS THAN (1970) );
Wenn Sie Partitionen mit REORGANIZE PARTITION
aufteilen oder zusammenführen, gehen keine Daten verloren. Bei
der Ausführung dieser Anweisung verschiebt MySQL alle
Datensätze, die zuvor in den Partitionen s0
und s1
gespeichert waren, wieder in die
Partition p0
.
REORGANIZE PARTITION
hat folgende allgemeine
Syntax:
ALTER TABLEtbl_name
REORGANIZE PARTITIONpartition_list
INTO (partition_definitions
);
tbl_name
ist hier der Name der
partitionierten Tabelle und
partition_list
ist eine
kommagetrennte Liste mit den Namen einer oder mehrerer
vorhandener Partitionen, die geändert werden sollen.
partition_definitions
ist eine
kommagetrennte Liste neuer Partitionsdefinitionen, für die
dieselben Regeln gelten, wie die
partition_definitions
einer
CREATE TABLE
-Anweisung (siehe
Abschnitt 13.1.5, „CREATE TABLE
“). Doch REORGANIZE
PARTITION
kann noch mehr, als nur Partitionen
aufspalten oder zusammenführen: Mit demselben Befehl können
Sie auch beispielsweise aus den vier Partitionen der
members
-Tabelle zwei machen:
ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO ( PARTITION m0 VALUES LESS THAN (1980), PARTITION m1 VALUES LESS THAN (2000) );
REORGANIZE PARTITION
ist auch für
LIST
-partitionierte Tabellen geeignet.
Greifen wir noch einmal das Problem auf, wie man eine neue
Partition zu der listenpartitionierten Tabelle
tt
hinzufügen könnte. Der Versuch
scheiterte, weil die neue Partition einen Wert hatte, der
bereits in den Wertelisten der vorhandenen Partitionen
auftauchte. Dies können wir umgehen, indem wir eine Partition
hinzufügen, deren Liste nur zulässige Werte enthält, und dann
die neue und die vorhandenen Partitionen so umorganisieren, dass
der konfliktbeladene Wert aus der Werteliste der alten in die
Werteliste der neuen Partition übertragen wird:
ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8)); ALTER TABLE tt REORGANIZE PARTITION p1,np INTO ( PARTITION p1 VALUES IN (6, 18), PARTITION np VALUES in (4, 8, 12) );
Die folgenden Punkte sind wichtig, wenn Sie ALTER TABLE
... REORGANIZE PARTITION
zur Neupartitionierung von
RANGE
- oder
LIST
-partitionierten Tabellen einsetzen:
Für die PARTITION
-Klauseln, mit denen
das neue Partitionierungsschema festgelegt wird, gelten
dieselben Regeln wie für die, die in einer CREATE
TABLE
-Anweisung benutzt werden.
Zuallererst müssen Sie daran denken, dass das neue
Partitionierungsschema keine sich überschneidenden
Wertebereiche (RANGE
-partitionierte
Tabellen) bzw. keine Überschneidungen in den Wertemengen
(LIST
-partitionierte Tabellen) haben
darf.
Hinweis: Vor MySQL 5.1.4
konnten Sie die Namen vorhandener Partitionen nicht in der
INTO
-Klausel wiederverwenden, selbst wenn
diese Partitionen gelöscht oder umdefiniert werden sollten.
Weitere Informationen gibt es unter
Abschnitt D.1.3, „Änderungen in Release 5.1.4 (21. Dezember 2005)“.
Die Kombination der Partitionen in der
partition_definitions
-Liste
sollte insgesamt denselben Wertebereich oder dieselbe
Wertemenge abdecken wie die Kombination der Partitionen, die
in der partition_list
aufgeführt
sind.
In der members
-Tabelle, die in diesem
Abschnitt als Beispiel dient, decken zum Beispiel die
Partitionen p1
und p2
zusammen die Jahre 1980 bis 1999 ab. Daher muss jede
Neuorganisation dieser beiden Partitionen insgesamt
denselben Zeitraum in Jahren abdecken.
In RANGE
-partitionierten Tabellen können
Sie nur benachbarte Partitionen reorganisieren, da keine
Bereichspartitionen übersprungen werden dürfen.
Sie können beispielsweise die
members
-Tabelle nicht mit einer Anweisung
reorganisieren, die mit ALTER TABLE members
REORGANIZE PARTITION p0,p2 INTO ...
anfängt, da
p0
die Jahre vor 1970 und
p2
die Jahre von 1990 bis einschließlich
1999 umfasst und somit die beiden Partitionen nicht
benachbart sind.
Sie können REORGANIZE PARTITION
nicht
einsetzen, um den Partitionierungstyp einer Tabelle zu
ändern, also beispielsweise nicht aus
RANGE
-Partitionen
HASH
-Partitionen oder umgekehrt machen.
Auch können Sie diesen Befehl nicht verwenden, um den
Partitionierungsausdruck oder die Partitionierungsspalte zu
ändern. Um dieses zu tun, ohne die Tabelle löschen und
rekonstruieren zu müssen, verwenden Sie ALTER
TABLE ... PARTITION BY ...
. Zum Beispiel:
ALTER TABLE members PARTITION BY HASH( YEAR(dob) ) PARTITIONS 8;
Hinweis: In MySQL 5.1
5.1.5-alpha ist ALTER TABLE ... PARTITION BY
...
noch nicht implementiert. Stattdessen müssen
Sie die Tabelle entweder löschen und mit der gewünschten
Partitionierung neu erzeugen oder, wenn Sie die Daten der
Tabelle bewahren möchten, mit CREATE TABLE ...
SELECT ...
die neue Tabelle anlegen und die Daten
aus der alten herüberkopieren, um anschließend die alte
Tabelle zu löschen und in einem letzten Schritt die neue
Tabelle umzubenennen, wenn dies gewünscht wird.
Die Partitionierung von Hash- oder schlüsselpartitionierten
Tabellen lässt sich in ähnlicher Weise ändern, wobei sich
Tabellen mit diesen beiden Formen der Partitionierung in
mehrerer Hinsicht von bereichs- oder listenpartitionierten
Tabellen unterscheiden. Daher werden in diesem Abschnitt nur
Änderungen von Hash- oder schlüsselpartitionierten Tabellen
behandelt. Das Hinzufügen und Löschen der Partitionen von
bereichs- oder listenpartitionierten Tabellen wird in
Abschnitt 17.3.1, „Verwaltung von RANGE
- und
LIST
-Partitionen“,
beschrieben.
Sie können Partitionen aus HASH
- oder
KEY
-partitionierten Tabellen nicht genauso
löschen wie aus RANGE
- oder
LIST
-partitionierten Tabellen. Doch zum
Zusammenführen von HASH
- oder
KEY
-partitionierten Tabellen können Sie
ebenfalls den ALTER TABLE ... COALESCE
PARTITION
-Befehl verwenden. Angenommen, Sie haben eine
Tabelle mit Kundendaten, die in 12 Partitionen aufgeteilt ist.
Diese clients
-Tabelle ist folgendermaßen
definiert:
CREATE TABLE clients ( id INT, fname VARCHAR(30), lname VARCHAR(30), signed DATE ) PARTITION BY HASH( MONTH(signed) ) PARTITIONS 12;
Um die Anzahl der Partitionen von 12 auf 6 zu reduzieren,
führen Sie folgenden ALTER TABLE
-Befehl aus:
mysql> ALTER TABLE clients COALESCE PARTITION 6;
Query OK, 0 rows affected (0.02 sec)
COALESCE
funktioniert genauso gut mit
HASH
-, KEY
-,
LINEAR HASH
- oder LINEAR
KEY
-partitionierten Tabellen. Hier sehen Sie ein
ähnliches Beispiel wie oben, allerdings dieses Mal mit einer
Tabelle, die nach LINEAR KEY
partitioniert
ist:
mysql>CREATE TABLE clients_lk (
->id INT,
->fname VARCHAR(30),
->lname VARCHAR(30),
->signed DATE
->)
->PARTITION BY LINEAR KEY(signed)
->PARTITIONS 12;
Query OK, 0 rows affected (0.03 sec) mysql>ALTER TABLE clients_lk COALESCE PARTITION 6;
Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0
COALESCE
kann nicht verwendet werden, um die
Anzahl der Partitionen zu erhöhen. Ein Versuch, dies zu tun,
verursacht folgenden Fehler:
mysql> ALTER TABLE clients COALESCE PARTITION 18;
ERROR 1478 (HY000): Cannot remove all Partitionen, use DROP TABLE instead
Um die Anzahl der Partitionen der
clients
-Tabelle von 12 auf 18 zu erhöhen,
erteilen Sie folgende ALTER TABLE ... ADD
PARTITION
-Anweisung:
ALTER TABLE clients ADD PARTITION PARTITIONS 18;
Hinweis: ALTER TABLE
... REORGANIZE PARTITION
kann nicht für
HASH
- oder
KEY
-partitionierte Tabellen verwendet werden.
Hinweis: Die Befehle, die dieser Abschnitt beschreibt, sind in MySQL 5.1 noch nicht implementiert. Sie werden vor allem vorgestellt, um Feedback von Benutzern zu bekommen, die die Software während des Entwicklungszyklus der Version 5.1 vor der Produktionsreife testen. (Mit anderen Worten: Bitte schicken Sie uns keine Bugreports mit dem Hinweis, dass diese Befehle nicht funktionieren.) Die Informationen in diesem Abschnitt ändern sich noch ständig, da die Entwicklung der Partitionierung für MySQL 5.1 weitergeht. Wir werden den Abschnitt aktualisieren, wenn Partitionierungsfeatures implementiert oder verbessert werden.
MySQL 5.1 ermöglicht viele Wartungsarbeiten im
Bereich der Partitionierung. MySQL unterstützt für
partitionierte Tabellen nicht die Befehle CHECK
TABLE
, OPTIMIZE TABLE
,
ANALYZE TABLE
oder REPAIR
TABLE
. Dagegen können Sie jedoch eine Reihe von
Erweiterungen des ALTER TABLE
-Befehls
einsetzen, um diese Operationen auf einer oder mehreren
Partitionen direkt auszuführen. Diese Erweiterungen sind im
Folgenden dargestellt:
Partitionen neu erstellen: Legt die Partition neu an, hat denselben Effekt wie das Löschen und anschließende Wiedereinfügen aller in der Partition gespeicherten Datensätze. Kann bei der Defragmentierung nützlich sein.
Beispiel:
ALTER TABLE t1 REBUILD PARTITION (p0, p1);
Partitionen optimieren:
Wenn Sie viele Zeilen aus einer Partition gelöscht oder
viele Änderungen an einer partitionierten Tabelle mit
Zeilen variabler Länge (VARCHAR
-,
BLOB
- oder
TEXT
-Spalten) vorgenommen haben, können
Sie mit ALTER TABLE ... OPTIMIZE
PARTITION
unbenutzten Speicherplatz zurückholen
und die Datendatei der Partition defragmentieren.
Beispiel:
ALTER TABLE t1 OPTIMIZE PARTITION (p0, p1);
Wenn Sie auf einer Partition OPTIMIZE
PARTITION
ausführen, ist dies dasselbe, als
würden Sie CHECK PARTITION
,
ANALYZE PARTITION
und REPAIR
PARTITION
aufrufen.
Partitionen analysieren: Liest und speichert die Schlüsselverteilungen für Partitionen.
Beispiel:
ALTER TABLE t1 ANALYZE PARTITION (p3);
Partitionen reparieren: Repariert beschädigte Partitionen.
Beispiel:
ALTER TABLE t1 REPAIR PARTITION (p0,p1);
Partitionen überprüfen:
Sie können Partitionen in ganz ähnlicher Weise auf Fehler
untersuchen, wie Sie es mit CHECK TABLE
für nicht partitionierte Tabellen machen würden.
Beispiel:
ALTER TABLE trb3 CHECK PARTITION (p1);
Dieser Befehl sagt Ihnen, ob die Daten oder Indizes in
Partition p1
der Tabelle
t1
beschädigt sind. Wenn dies der Fall
ist, können Sie die Partition mit ALTER TABLE ...
REPAIR PARTITION
wieder reparieren.
Diese Aufgaben können Sie auch lösen, indem Sie
mysqlcheck oder myisamchk
auf den separaten .MYI
-Dateien ausführen,
die bei der Partitionierung einer Tabelle generiert werden.
Siehe Abschnitt 8.9, „mysqlcheck — Hilfsprogramm für die Wartung und Reparatur von Tabellen“. (Diese Möglichkeit steht
auch bereits im Pre-Alpha-Code zur Verfügung.)
Dieser Abschnitt beschreibt, wie Sie sich Informationen über bestehende Partitionen beschaffen können. Da sich diese Funktionalität noch in der Planung befindet, sind die folgenden Ausführungen zurzeit nur eine Absichtserklärung über die Dinge, die wir in MySQL 5.1 implementieren wollen.
Wie bereits an anderer Stelle in diesem Kapitel gesagt, zeigt
die Ausgabe von SHOW CREATE TABLE
auch eine
PARTITION BY
-Klausel an, mit der eine
partitionierte Tabelle angelegt wurde. Zum Beispiel:
mysql> SHOW CREATE TABLE trb3\G
*************************** 1. row ***************************
Table: trb3
Create Table: CREATE TABLE `trb3` (
`id` int(11) default NULL,
`name` varchar(50) default NULL,
`purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE (YEAR(purchased)) (
PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (2000) ENGINE = MyISAM,
PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.00 sec)
Hinweis: In frühen MySQL
5.1-Releases wurde die PARTITIONS
-Klausel
nicht für Tabellen angezeigt, die nach HASH
oder KEY
partitioniert waren. Dies wurde in
MySQL 5.1.6 behoben.
SHOW TABLE STATUS
funktioniert auch für
partitionierte Tabellen und hat dieselbe Ausgabe wie für
nichtpartitionierte Tabellen, nur dass die Spalte
Engine
immer den Wert
'PARTITION'
hat. (Mehr über diesen Befehl
erfahren Sie in Abschnitt 13.5.4.21, „SHOW TABLE STATUS
“.)
Informationen über Partitionen liefert Ihnen auch das
INFORMATION_SCHEMA
, zu dem auch eine
PARTITIONS
-Tabelle gehört. Siehe
Abschnitt 22.19, „Die Tabelle INFORMATION_SCHEMA PARTITIONS
“.
Seit MySQL 5.1.5 können Sie mit EXPLAIN
PARTITIONS
herausfinden, welche Partitionen einer
partitionierten Tabelle an einer
SELECT
-Anfrage beteiligt sind. Das
Schlüsselwort PARTITIONS
fügt der Ausgabe
von EXPLAIN
eine
partitions
-Spalte hinzu, in der die
Partitionen aufgeführt sind, in denen die Anfrage Datensätze
erkannt hat.
Angenommen, Sie haben eine Tabelle trb1
, die
folgendermaßen definiert und mit Daten gefüllt ist:
CREATE TABLE trb1 (id INT, name VARCHAR(50), purchased DATE) PARTITION BY RANGE(id) ( PARTITION p0 VALUES LESS THAN (3), PARTITION p1 VALUES LESS THAN (7), PARTITION p2 VALUES LESS THAN (9), PARTITION p3 VALUES LESS THAN (11) ); INSERT INTO trb1 VALUES (1, 'desk organiser', '2003-10-15'), (2, 'CD player', '1993-11-05'), (3, 'TV set', '1996-03-10'), (4, 'bookcase', '1982-01-10'), (5, 'exercise bike', '2004-05-09'), (6, 'sofa', '1987-06-05'), (7, 'popcorn maker', '2001-11-22'), (8, 'aquarium', '1992-08-04'), (9, 'study desk', '1984-09-16'), (10, 'lava lamp', '1998-12-25');
Mit folgendem Befehl können Sie sich darüber informieren,
welche Partitionen in einer Anfrage wie SELECT * FROM
trb1;
benutzt werden:
mysql> EXPLAIN PARTITIONS SELECT * FROM trb1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: trb1
partitions: p0,p1,p2,p3
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 10
Extra: Using filesort
In diesem Fall wurden 4 vier Partitionen durchsucht. Wenn Sie der Anfrage jedoch eine einschränkende Bedingung hinzufügen, die den Partitionierungsschlüssel enthält, können Sie erkennen, dass nur diejenigen Partitionen gescannt werden, die passende Werte enthalten:
mysql> EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: trb1
partitions: p0,p1
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 10
Extra: Using where
EXPLAIN PARTITIONS
informiert über
verwendete und mögliche Schlüssel ebenso wie die
standardmäßige EXPLAIN SELECT
-Anweisung:
mysql>ALTER TABLE trb1 ADD PRIMARY KEY (id);
Query OK, 10 rows affected (0.03 sec) Records: 10 Duplicates: 0 Warnings: 0 mysql>EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: trb1 partitions: p0,p1 type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 7 Extra: Using where
Beachten Sie jedoch folgende Restriktionen von EXPLAIN
PARTITIONS
:
Sie dürfen die Schlüsselwörter
PARTITIONS
und
EXTENDED
nicht zusammen in derselben
EXPLAIN ... SELECT
-Anweisung benutzen,
sonst verursachen Sie einen Syntaxfehler.
Der Befehl EXPLAIN PARTITIONS
liefert nur
dann brauchbare Ergebnisse, wenn er zur Untersuchung von
Anfragen auf RANGE
- oder
LIST
-partitionierten Tabellen verwendet
wird. (Bei KEY
- oder
HASH
-partitionierten Tabellen listet der
Befehl einfach alle Partitionen in der
partitions
-Spalte seiner Ausgabe auf.)
Wenn Sie mit EXPLAIN PARTITIONS
eine
Anfrage auf einer nichtpartitionierten Tabelle untersuchen,
wird zwar kein Fehler ausgelöst, aber der Wert der
partitions
-Spalte ist dann immer
NULL
.
EXPLAIN PARTITIONS
funktioniert zurzeit
nur mit Tabellen, die auf einer Integer-Spalte partitioniert
werden.
Dieser Abschnitt beschreibt die gegenwärtigen Restriktionen der MySQL-Partitionierungsunterstützung:
Partitionierte Tabellen unterstützen keine Fremdschlüssel.
Dies schließt auch Tabellen ein, die mit der Speicher-Engine
InnoDB
arbeiten.
Partitionierte Tabellen können zwar jede beliebige Speicher-Engine von MySQL benutzen, aber alle Partitionen und Teilpartitionen der Tabelle (wenn vorhanden) müssen dieselbe Engine verwenden.
Wir hoffen, diese Beschränkung in einem künftigen MySQL-Release aufzuheben.
Ein Partitionierungsschlüssel muss entweder eine
Integer-Spalte oder ein Ausdruck sein, der einen Integer
ergibt. In jedem Fall muss der verwendete Wert nichtnegativ
sein. Zurzeit sind auch NULL
-Werte
zulässig, aber dies wird sich noch ändern.
Teilpartitionen können nur HASH
- oder
KEY
-Partitionierung verwenden.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.