Pour avoir un index partiel de type PostgreSQL dans MySQL 5.5

9

J'ai des données volumineuses où je ne sélectionne qu'un petit intervalle de données à la fois de telle sorte que la sélection est toujours dans une séquence. J'essaie d'implémenter PostgreSQL comme l'index partiel dans MySQL qui est ciblé à de telles fins. Je ne sais pas si la contrainte unique partielle est la même que celle que je souhaite.

Code dans PostgreSQL 9.4

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

Tentative sur l'index partiel de ypercube dans MySQL

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

Comment pouvez-vous créer un index partiel de type PostgreSQL dans MySQL 5.5 ou similaire?

Léo Léopold Hertz 준영
la source
4
MySQL n'a pas implémenté d'index partiels. Vous pouvez ajouter une autre table dans votre conception qui stocke uniquement les lignes avec is_active = TRUE(ou n'a qu'une seule colonne, le PK de dir_events).
ypercubeᵀᴹ

Réponses:

13

Ni MySQL ni les frères et sœurs (MariaDB, Drizzle, etc.) n'ont implémenté des index partiels.

Ce que vous pouvez faire, avec cette restriction à l'esprit:

  • a) faire un index simple (non partiel) sur (is_active, measurement_id). Il sera utilisé dans les requêtes où l'index partiel le ferait. Bien sûr, si la is_activecolonne est vraie à 3% et fausse à 97%, cet index sera beaucoup plus grand (qu'un index partiel). Mais toujours plus petit que le tableau et utile pour ces requêtes.
    Une autre limitation est que l'index ne peut pas être UNIQUEavec cette solution, donc la contrainte n'est pas appliquée. Si l'index est créé avec UNIQUE, l'unicité sera également appliquée pour les lignes avec is_active = FALSE. Je suppose que vous ne voulez pas ça:

    CREATE INDEX dir_events
        ON events (is_active, measurement_id)
        USING btree ;
    
  • b1) (la variante simple de b): ajoutez une autre table dans votre conception, avec uniquement les colonnes de clé primaire de eventset une clé étrangère vers events. Ce tableau ne doit avoir que des lignes où le is_activeest vrai dans le tableau d'origine (cela sera appliqué par votre application / procédures). Les requêtes avec is_active = TRUEseraient modifiées pour se joindre à cette table (au lieu de la WHEREcondition).
    Le UNIQUEn'est pas appliqué non plus avec cette solution, mais les requêtes ne feraient qu'une simple jointure (à un index beaucoup plus petit) et devraient être assez efficaces:

    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) une solution plus complexe: ajoutez une autre table dans votre conception, avec uniquement les colonnes de clé primaire de la table etmeasurement_id . Comme dans la suggestion précédente, ce tableau ne devrait avoir que des lignes où le is_activeest vrai dans le tableau d'origine (cela sera également appliqué par votre application / procédures). Utilisez ensuite ce tableau uniquement pour les requêtes qui ont WHERE is_active = TRUEet n'ont besoin que de la measurement_idcolonne. Si eventsvous avez besoin de plus de colonnes , vous devrez join, comme précédemment.
    La UNIQUEcontrainte peut être appliquée avec cette solution. La duplication de measurement_idcolonne peut également être sécurisée pour être cohérente (avec une contrainte unique supplémentaire eventset une clé étrangère composite):

    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) peut-être le plus simple de tous: utilisez PostgreSQL. Je suis sûr qu'il existe des packages pour votre distribution Linux. Ce n'est peut-être pas la dernière version de Postgres, mais des index partiels ont été ajoutés dans la version 7.0 (ou antérieure?), Vous ne devriez donc pas avoir de problème. De plus, je suis convaincu que vous pouvez installer la dernière version dans presque toutes les distributions Linux - même avec un peu de tracas. Vous n'avez besoin de l'installer qu'une seule fois.

ypercubeᵀᴹ
la source
Très bonne réponse. Segway: Le wiki sur les index partiels cite un blog "Dans MySQL, le terme" index partiel "est parfois utilisé pour faire référence aux index préfixes" qui n'est mentionné nulle part dans les documents MySQL. C'est une terminologie confuse inventée sur ce blog. Le blog affirme également que les index de préfixe sont plus petits / performants, ce qui dépendrait. Un préfixe de chaîne créerait un btree avec moins de profondeur, mais plus de pages par feuille, donc les analyses d'index peuvent être plus rapides; cherche serait plus lent. Utilisez également PostgreSQL! La première mention PG que j'ai trouvée est ce document étrangement op-ed dans la version 7.0 postgresql.org/docs/7.0/partial-index.htm
Davos
0

Ce n'est pas idéal, mais si vous avez une validation sur le terrain, vous pouvez apporter une modification qui rend la valeur non valide. Par exemple, des caractères illégaux ou des nombres négatifs. Vous pouvez effectuer cette modification lors de la suppression logicielle et vous savez qu'elle n'entrera pas en conflit avec une valeur valide. Vous devez également surveiller les valeurs supprimées en douceur qui ne s'affrontent pas également.

Dans 1 cas, j'avais une colonne de courrier électronique avec une contrainte unique et un identifiant d'entier à incrémentation automatique pour chaque ligne. Lors de la suppression logicielle, j'ai ajouté "id @", où id était l'ID de ligne unique, avant le véritable e-mail. @n'est pas autorisé dans les e-mails sauf s'il est cité, donc je sais qu'aucun e-mail valide n'entrera en conflit avec la nouvelle valeur, et donc cela n'entrera jamais en conflit avec un e-mail valide. L'ID entier unique garantit également que chaque ligne supprimée sera unique, même si le même e-mail est supprimé plusieurs fois.

Je sais que ce n'est pas idéal, mais c'est un moyen simple de contourner le problème.

REMARQUE: Le changement que je mentionne ajoute des caractères au champ unique, j'ai donc dû faire des astuces supplémentaires si la valeur actuelle est déjà à / près de la longueur maximale. Ils sont spécifiques à l'application, donc ne valent pas la peine d'être mentionnés ici, mais soyez conscients et trouvez une solution de contournement pour cela aussi et c'est un moyen simple de contourner le manque de la fonctionnalité d'index partiel.

Charles L.
la source