PostgreSQL-ähnlichen Teilindex in MySQL 5.5

9

Ich habe große Datenmengen, bei denen ich jeweils nur ein kleines Datenintervall auswähle, sodass die Auswahl immer in einer Reihenfolge erfolgt. Ich versuche, PostgreSQL wie Partial Index in MySQL zu implementieren, der für solche Zwecke vorgesehen ist. Ich bin nicht sicher, ob die teilweise eindeutige Einschränkung dieselbe ist wie die, die ich möchte.

Code in PostgreSQL 9.4

CREATE UNIQUE INDEX dir_events
    ON events (measurement_id)
    USING btree
    (eventBody)
    WHERE is_active;

Versuch des Teilindex von ypercube in MySQL

CREATE UNIQUE INDEX dir_events
    [index_type] -- TODO what here?
    ON events (measurement_id, is_active)
    [index_type] -- TODO what here?

Wie können Sie einen PostgreSQL-ähnlichen Teilindex in MySQL 5.5 oder ähnlichem erstellen?

Léo Léopold Hertz 준영
quelle
4
MySQL hat keine Teilindizes implementiert. Sie können Ihrem Entwurf eine weitere Tabelle hinzufügen, in der nur die Zeilen mit is_active = TRUE(oder nur eine Spalte, die PK von dir_events) gespeichert sind .
Ypercubeᵀᴹ

Antworten:

13

Weder MySQL noch die Geschwister (MariaDB, Drizzle usw.) haben Teilindizes implementiert.

Was Sie unter Berücksichtigung dieser Einschränkung tun können:

  • a) Machen Sie einen einfachen (nicht partiellen) Index auf (is_active, measurement_id). Es wird in Abfragen verwendet, in denen der Teilindex verwendet wird. Wenn die is_activeSpalte 3% Wahr und 97% Falsch ist, ist dieser Index natürlich viel größer (als ein Teilindex). Aber immer noch kleiner als die Tabelle und nützlich für diese Abfragen.
    Eine weitere Einschränkung ist, dass der Index UNIQUEbei dieser Lösung nicht vorhanden sein kann, sodass die Einschränkung nicht erzwungen wird. Wenn der Index mit erstellt wird UNIQUE, wird die Eindeutigkeit auch für Zeilen mit erzwungen is_active = FALSE. Ich nehme an, das willst du nicht:

    CREATE INDEX dir_events
        ON events (is_active, measurement_id)
        USING btree ;
  • b1) (die einfache Variante von b): Fügen Sie Ihrem Entwurf eine weitere Tabelle hinzu, zu der nur die Primärschlüsselspalten eventsund ein Fremdschlüssel gehören events. Diese Tabelle sollte nur Zeilen enthalten, in denen das is_activein der Originaltabelle wahr ist (dies wird von Ihrer Anwendung / Ihren Prozeduren erzwungen). Abfragen mit is_active = TRUEwürden geändert, um dieser Tabelle beizutreten (anstelle der WHEREBedingung).
    Die UNIQUEAbfrage wird auch mit dieser Lösung nicht erzwungen, aber die Abfragen würden nur eine einfache Verknüpfung (zu einem viel kleineren Index) durchführen und sollten recht effizient sein:

    CREATE TABLE events_active
    ( event_id INT NOT NULL,         -- assuming an INT primary key on events
      PRIMARY KEY (event_id),
      FOREIGN KEY (event_id)
        REFERENCES events (event_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id)
    SELECT event_id
    FROM events
    WHERE is_active = TRUE ;
  • b2) eine komplexere Lösung: Fügen Sie Ihrem Entwurf eine weitere Tabelle hinzu, die nur die Primärschlüsselspalten der Tabelle und enthältmeasurement_id . Wie im vorherigen Vorschlag sollte diese Tabelle nur Zeilen enthalten, in denen die is_activeursprüngliche Tabelle wahr ist (dies wird auch von Ihrer Anwendung / Ihren Prozeduren erzwungen). Verwenden Sie diese Tabelle dann stattdessen nur für Abfragen, die WHERE is_active = TRUEnur die measurement_idSpalte haben und benötigen . Wenn mehr Spalten von benötigt werden events, müssen Sie joinwie zuvor.
    Die UNIQUEEinschränkung kann mit dieser Lösung erzwungen werden. Das Duplizieren der measurement_idSpalte kann auch so gesichert werden, dass es konsistent ist (mit einer zusätzlichen eindeutigen Einschränkung eventsund einem zusammengesetzten Fremdschlüssel):

    ALTER TABLE events
      ADD UNIQUE (event_id, measurement_id) ;
    
    CREATE TABLE events_active
    ( event_id INT NOT NULL,
      measurement_id INT NOT NULL.
      PRIMARY KEY (event_id, measurement_id),
      UNIQUE (measurement_id),
      FOREIGN KEY (event_id, measurement_id)
        REFERENCES events (event_id, measurement_id)
    ) ;
    
    INSERT INTO events_active 
      (event_id, measurement_id)
    SELECT event_id, measurement_id
    FROM events
    WHERE is_active = TRUE ;
  • c) vielleicht das einfachste von allen: Verwenden Sie PostgreSQL. Ich bin sicher, es gibt Pakete für Ihre Linux-Distribution. Möglicherweise handelt es sich nicht um die neueste Version von Postgres, aber in 7.0 (oder früher?) Wurden Teilindizes hinzugefügt, sodass Sie kein Problem haben sollten. Außerdem bin ich zuversichtlich, dass Sie die neueste Version in fast jeder Linux-Distribution installieren können - auch mit ein wenig Aufwand. Sie müssen es nur einmal installieren.

ypercubeᵀᴹ
quelle
Gute Antwort. Segway: Das Wiki zu Teilindizes zitiert ein Blog "In MySQL wird der Begriff" Teilindex "manchmal verwendet, um auf Präfixindizes zu verweisen", was in den MySQL-Dokumenten nirgends angegeben ist. Es ist eine verwirrte Terminologie, die in diesem Blog geprägt wurde. Der Blog behauptet auch, dass Präfixindizes kleiner / performanter sind, was davon abhängen würde. Ein Zeichenfolgenpräfix würde einen Baum mit geringerer Tiefe und dennoch mehr Seiten pro Blatt erstellen, sodass Index-Scans möglicherweise schneller sind. sucht wäre langsamer. Verwenden Sie auch PostgreSQL! Die erste PG-Erwähnung, die ich gefunden habe, ist dieses seltsam aufgerufene
Davos
0

Es ist nicht ideal, aber wenn Sie eine Validierung für das Feld haben, können Sie eine Änderung vornehmen, die den Wert ungültig macht. Zum Beispiel unzulässige Zeichen oder negative Zahlen. Sie können diese Änderung beim Soft-Löschen vornehmen und wissen, dass sie nicht mit einem gültigen Wert kollidiert. Sie müssen auch auf weiche gelöschte Werte achten, die nicht miteinander in Konflikt geraten.

In einem Fall hatte ich eine E-Mail-Spalte mit einer eindeutigen Einschränkung und einer Integer-ID für die automatische Inkrementierung für jede Zeile. Beim sanften Löschen habe ich vor der eigentlichen E-Mail "id @" hinzugefügt, wobei id die eindeutige Zeilen-ID war. @ist in E-Mails nur zulässig, wenn sie in Anführungszeichen gesetzt sind. Daher weiß ich, dass keine gültige E-Mail mit dem neuen Wert kollidiert und daher niemals mit einer gültigen E-Mail kollidiert. Die eindeutige Ganzzahl-ID garantiert auch, dass jede gelöschte Zeile eindeutig ist, selbst wenn dieselbe E-Mail mehrmals gelöscht wird.

Ich weiß, dass dies nicht ideal ist, aber es ist eine einfache Möglichkeit, das Problem zu umgehen.

HINWEIS: Die von mir erwähnte Änderung fügt dem eindeutigen Feld Zeichen hinzu , sodass ich zusätzliche Tricks ausführen musste, wenn der aktuelle Wert bereits bei / nahe der maximalen Länge liegt. Sie sind anwendungsspezifisch, daher hier nicht erwähnenswert. Beachten Sie jedoch auch eine Problemumgehung, und dies ist eine einfache Möglichkeit, um das Fehlen der Teilindexfunktion zu umgehen.

Charles L.
quelle