1. Indexkonzept und Anwendung
1.1 Was ist ein Index
Ein Index ist eine Datenstruktur, die in einem Datenbankmanagementsystem zur Beschleunigung von Datenabrufoperationen verwendet wird. Man kann ihn sich als "Verzeichnis" in der Datenbank vorstellen, das die schnelle Lokalisierung von Daten in einer Datentabelle ermöglicht, vollständige Tabellenscans vermeidet und die Abfrageeffizienz erheblich verbessert. In der praktischen Anwendung kann die richtige Verwendung von Indizes die Leistung einer Datenbank erheblich steigern.
1.2 Arten von Indizes
Es gibt verschiedene Arten von Indizes, von denen jede ihr eigenes Design und ihre eigene Optimierung für unterschiedliche Anwendungsszenarien aufweist:
- Einfeldindex: Ein Index, der nur ein Feld umfasst und für Szenarien geeignet ist, die auf eine einzige Bedingung für schnelle Abfragen angewiesen sind.
- Zusammengesetzter Index: Ein Index, der mehrere Felder umfasst und eine Optimierung für Abfragen bietet, die diese Felder enthalten.
- Eindeutiger Index: Gewährleistet die Eindeutigkeit von Indexfeldern und lässt keine doppelten Werte zu. Eindeutige Indizes können Einfeld- oder zusammengesetzt sein.
2. Indexdefinition
2.1 Feldindexdefinition
Die Erstellung eines Einfeldindexes beinhaltet die Einrichtung eines Index für eine bestimmte Spalte einer Datentabelle, die mit der Methode Fields
erreicht werden kann. Das folgende Beispiel zeigt, wie man einen Index für das Telefon
-Feld der Entität Benutzer
erstellt.
func (Benutzer) Fields() []ent.Field {
return []ent.Field{
field.String("Telefon"),
}
}
func (Benutzer) Indexes() []ent.Index {
// Einen Einfeldindex erstellen.
return []ent.Index{
index.Fields("Telefon"),
}
}
In diesem Code-Snippet wird das Telefon
-Feld indiziert. Dadurch kann das System den Index für schnellere Suchvorgänge bei Abfragen des Telefon
-Felds nutzen.
2.2 Eindeutige Indexdefinition
Ein eindeutiger Index gewährleistet die Eindeutigkeit der Daten in den indizierten Spalten. Er kann erstellt werden, indem man der Spalte die Methode Unique
hinzufügt. Die folgenden Beispiele veranschaulichen die Erstellung von eindeutigen Indizes für Einzelfelder und mehrere Felder.
Erstellung eines eindeutigen Index für ein einzelnes Feld:
func (Benutzer) Fields() []ent.Field {
return []ent.Field{
field.String("E-Mail").Unique(),
}
}
In diesem Beispiel wird das E-Mail
-Feld als eindeutig definiert, um sicherzustellen, dass die E-Mail jedes Benutzers in der Datenbank eindeutig ist.
Erstellung eines eindeutigen Index für eine Kombination mehrerer Felder:
func (Benutzer) Indexes() []ent.Index {
return []ent.Index{
// Erstellen eines eindeutigen Index für mehrere Felder.
index.Fields("Vorname", "Nachname").Unique(),
}
}
Dieser Code definiert einen zusammengesetzten eindeutigen Index für die Kombination der Felder Vorname
und Nachname
, um das Auftreten von Datensätzen mit gleichen Werten in beiden Feldern zu verhindern.
2.3 Definition eines zusammengesetzten Index
Wenn die Abfragebedingungen mehrere Felder umfassen, kann ein zusammengesetzter Index zum Einsatz kommen. Der zusammengesetzte Index speichert Daten in der im Index definierten Reihenfolge. Die Reihenfolge des Index hat einen erheblichen Einfluss auf die Abfrageleistung, daher muss bei der Definition eines zusammengesetzten Index die Reihenfolge der Felder basierend auf dem Abfrage-Muster festgelegt werden.
Hier ist ein Beispiel für die Erstellung eines zusammengesetzten Index:
func (Benutzer) Indexes() []ent.Index {
return []ent.Index{
// Erstellen eines zusammengesetzten Index mit mehreren Feldern.
index.Fields("Land", "Stadt"),
}
}
In diesem Beispiel wird ein zusammengesetzter Index für die Felder Land
und Stadt
erstellt. Das bedeutet, dass die Datenbank bei Abfragevorgängen, die diese beiden Felder betreffen, schnell die den Bedingungen entsprechenden Daten lokalisieren kann.
Ein zusammengesetzter Index beschleunigt nicht nur die Abfrageleistung, sondern unterstützt auch sortierte Operationen auf der Grundlage von Indizes und bietet eine effizientere Datenabrufleistung. Bei der Gestaltung eines zusammengesetzten Index ist es üblich, die Felder mit höherer Selektivität am Anfang des Index zu platzieren, damit der Datenbankoptimierer den Index besser nutzen kann.
3. Edge-Indizes
Im ent-Framework dienen Edge-Indizes dazu, Indizes über Kanten (Beziehungen) zu definieren. Dieser Mechanismus wird typischerweise genutzt, um die Eindeutigkeit von Feldern unter spezifischen Beziehungen zu gewährleisten. Zum Beispiel, wenn Ihr Datenbankmodell Städte und Straßen beinhaltet und jeder Straßenname unter einer Stadt eindeutig sein muss, können Edge-Indizes genutzt werden, um dies zu erreichen.
// Die Datei ent/schema/street.go definiert das Schema für die Street-Entität.
type Street struct {
ent.Schema
}
func (Street) Fields() []ent.Field {
// Felder definieren
return []ent.Field{
field.String("name"),
}
}
func (Street) Edges() []ent.Edge {
// Die Kantenbeziehung zu City definieren, wo Street zu einer City gehört.
return []ent.Edge{
edge.From("city", City.Type).
Ref("streets").
Unique(),
}
}
func (Street) Indexes() []ent.Index {
// Einen eindeutigen Index über die Kante erstellen, um die Eindeutigkeit der Straßennamen innerhalb derselben Stadt zu gewährleisten.
return []ent.Index{
index.Fields("name").
Edges("city").
Unique(),
}
}
In diesem Beispiel erstellen wir eine Street
-Entität und verknüpfen sie mit der City
-Entität. Durch die Definition eines Edge-Indizes in der Indexes
-Methode der Street
-Entität stellen wir sicher, dass der Name jeder Straße unter einer Stadt eindeutig ist.
Kapitel 5: Erweiterte Indexoptionen
5.1 Volltext- und Hash-Indizes
Volltext- und Hash-Indizes sind zwei einzigartige Indexarten in MySQL und PostgreSQL und werden für unterschiedliche Abfrageoptimierungsszenarien verwendet.
Volltext-Indizes werden üblicherweise für die Suche nach Textdaten verwendet, insbesondere wenn komplexe Suchvorgänge wie Wortübereinstimmungssuchen durchgeführt werden müssen. Sowohl MySQL als auch PostgreSQL-Datenbanken unterstützen die Volltext-Indizierung. Zum Beispiel können Sie in MySQL einen Volltext-Index wie folgt definieren:
// Die Datei ent/schema/user.go definiert das Schema für die User-Entität
func (User) Indexes() []ent.Index {
// Einen Volltext-Index unter Verwendung der FULLTEXT-Kategorie in MySQL erstellen
return []ent.Index{
index.Fields("description").
Annotations(entsql.IndexTypes(map[string]string{
dialect.MySQL: "FULLTEXT",
})),
}
}
Hash-Indizes eignen sich besonders für Gleichheitsabfragen und unterstützen kein Sortieren und Bereichsabfragen. In PostgreSQL können Sie einen Hash-Index wie folgt verwenden:
func (User) Indexes() []ent.Index {
// Einen Index vom Typ HASH definieren
return []ent.Index{
index.Fields("c4").
Annotations(entsql.IndexType("HASH")),
}
}
5.2 Partielle Indizes und Indexpräfixe
Ein partieller Index ist eine Art Index, die nur die Zeilen in einer Tabelle indiziert, die bestimmte Bedingungen erfüllen. In SQLite und PostgreSQL können Sie die WHERE-Klausel verwenden, um partielle Indizes zu erstellen.
Beispiel für die Definition eines partiellen Index in PostgreSQL:
func (User) Indexes() []ent.Index {
// Einen partiellen Index auf dem Feld "nickname" erstellen, der nur Zeilen enthält, bei denen "active" wahr ist
return []ent.Index{
index.Fields("nickname").
Annotations(
entsql.IndexWhere("active"),
),
}
}
Ein Indexpräfix ist besonders nützlich für Textfelder, insbesondere in MySQL. Es kann die Indexerstellungsdauer verkürzen, den vom Index belegten Speicherplatz reduzieren und zudem eine gute Leistung bieten. Wie unten gezeigt, können Sie für MySQL einen Index mit einem Präfix definieren:
func (User) Indexes() []ent.Index {
// Einen Index unter Verwendung eines Indexpräfixes erstellen
return []ent.Index{
index.Fields("description").
Annotations(entsql.Prefix(128)),
}
}
5.3 Index-Anmerkungen und Anpassung
In ent ist Annotations
ein Feature, das es Entwicklern ermöglicht, Indizes flexibel anzupassen. Sie können den Indextyp definieren, Sortierregeln festlegen und mehr.
Zum Beispiel zeigt der folgende Code, wie die Spaltensortierregeln in einem Index spezifiziert werden:
func (User) Indexes() []ent.Index {
return []ent.Index{
// Annotationen verwenden, um die Spaltensortierregeln des Index zu definieren
index.Fields("c1", "c2", "c3").
Annotations(entsql.DescColumns("c1", "c2")),
}
}
Durch das Annotations-Feature können Entwickler Indizes flexibel anpassen, um die Leistung und Struktur der Datenbank zu optimieren.