2010-03-23 7 views
2

J'ai une table MySQL InnoDB avec une colonne d'état. Le statut peut être 'fait' ou 'traitement'. Au fur et à mesure que la table grossit, au plus 0,1% des valeurs de statut seront 'traitées', alors que les 99,9% restants seront 'terminés'. Cela semble être un bon candidat pour un indice en raison de la haute sélectivité pour le «traitement» (mais pas pour «fait»). Est-il possible de créer un index pour la colonne d'état qui indexe seulement la valeur 'traitement'? Je ne veux pas que l'index gaspille énormément d'espace d'indexation 'fait'.Indexation d'une seule valeur de colonne MySQL

+0

Je me demandais simplement s'il serait plus facile de convertir dans une colonne binaire nommée "processing" où la valeur serait "1" ou "0". Utiliserait moins d'espace. (Sauf si vous avez plus de 2 statuts) –

+0

Bonne suggestion. En fait, j'ai plus de 2 statuts, mais je l'ai simplifié pour des raisons de simplicité. – BrainCore

+0

"mais je l'ai simplifié pour des raisons de simplicité" - c'est correct alors, tant que vous ne l'avez pas simplifié pour une autre raison :-) – paxdiablo

Répondre

3

Je ne suis pas au courant d'aucune manière standard pour ce faire, mais nous avons résolu un problème similaire avant en utilisant deux tables, Processing et Done dans votre cas, le premier avec un index, le dernier sans.

En supposant que les lignes ne jamais basculer en arrière done-processing, voici les étapes que vous pouvez utiliser:

  1. Lorsque vous créez un enregistrement, l'insérer dans la table Processing avec la colonne mis à processing.
  2. Une fois l'opération terminée, définissez la colonne sur done.
  3. Balayez régulièrement la table , en déplaçant les lignes done vers la table Done.

Ce dernier peut être difficile. Vous pouvez faire l'insertion/suppression dans une transaction pour vous assurer qu'il transfère correctement ou vous pouvez utiliser un identifiant unique pour détecter s'il est déjà transféré et ensuite le supprimer de Processing (je n'ai aucune expérience avec le support des transactions MySQL, c'est pourquoi je suis donnant aussi cette option). De cette manière, vous n'indexez que quelques-unes des 99,9% des lignes done, celles qui n'ont pas encore été transférées dans la table Done. Il fonctionnera également avec plusieurs états de processing comme vous l'avez mentionné dans les commentaires (les entrées ne sont transférées que lorsqu'elles atteignent l'état done, tous les autres états restent dans la table Processing).

Cela équivaut à avoir des données historiques (des données qui ne changeront plus jamais) transférées dans un tableau distinct pour plus d'efficacité. Cela peut compliquer certaines requêtes où vous devez accéder aux lignes done et non done puisque vous devez joindre deux tables, sachez donc qu'il y a un compromis.

0

Meilleure solution: n'utilisez pas de chaînes pour indiquer les états. Utilisez plutôt des constantes dans votre code avec des noms descriptifs => valeurs entières. Alors cet entier est stocké dans la base de données, et MySQL fonctionnera beaucoup plus rapidement qu'avec des chaînes.

Je ne sais pas quelle langue que vous utilisez, mais par exemple en PHP:

class Member 
{ 
    const STATUS_ACTIVE = 1; 
    const STATUS_BANNED = 2; 
} 

if ($member->getStatus() == Member::STATUS_ACTIVE) 
{ 
} 

au lieu de ce que vous avez maintenant:

if ($member->getStatus() == 'active') 
{ 
} 
+0

Merci pour la réponse.Les chaînes sont en fait des ENUM, ce qui signifie qu'elles sont mises en correspondance avec des entiers. Bien que votre suggestion soit valable, elle ne va pas à la racine de ma question: est-il nécessaire de, et si oui comment, indexer seulement une valeur spécifique dans une colonne? – BrainCore

Questions connexes