75 votes

Quand est-il préférable de stocker les drapeaux sous forme de masque de bits plutôt que d'utiliser une table associative ?

Je travaille sur une application où les utilisateurs ont différentes autorisations pour utiliser différentes fonctionnalités (par exemple, lire, créer, télécharger, imprimer, approuver, etc.) La liste des autorisations ne devrait pas changer souvent. J'ai plusieurs possibilités pour stocker ces autorisations dans la base de données.

Dans quels cas l'option 2 serait-elle meilleure ?

Option 1

Utilisez une table associative.

User
----
UserId (PK)
Name
Department
    Permission
----
PermissionId (PK)
Name    User\_Permission
----
UserId (FK)
PermissionId (FK)

Option 2

Stocke un masque de bits pour chaque utilisateur.

User
----
UserId (PK)
Name
Department
Permissions

[Flags]
enum Permissions {
    Read = 1,
    Create = 2,
    Download = 4,
    Print = 8,
    Approve = 16
}

63voto

Neville K Points 13666

Excellente question !

Tout d'abord, formulons quelques hypothèses sur le terme "meilleur".

Je suppose que vous ne vous souciez pas beaucoup de l'espace disque - un masque de bits est efficace du point de vue de l'espace, mais je ne suis pas sûr que cela ait beaucoup d'importance si vous utilisez le serveur SQL.

Je suppose que vous vous souciez de la vitesse. Un masque de bits peut être très rapide lors de l'utilisation de calculs - mais vous ne pourrez pas utiliser d'index lors de l'interrogation du masque de bits. Cela ne devrait pas avoir beaucoup d'importance, mais si vous voulez savoir quels utilisateurs ont un accès de création, votre requête serait quelque chose comme

select * from user where permsission & CREATE = TRUE

(je n'ai pas accès à SQL Server aujourd'hui, je suis sur la route). Cette requête ne pourrait pas utiliser d'index à cause de l'opération mathématique - donc si vous avez un grand nombre d'utilisateurs, ce serait assez pénible.

Je suppose que vous vous souciez de la maintenabilité. Du point de vue de la maintenabilité, le bitmask n'est pas aussi expressif que le stockage de permissions explicites pour le domaine du problème sous-jacent. Il est presque certain que vous devrez synchroniser la valeur des drapeaux bitmask sur plusieurs composants, y compris la base de données. Ce n'est pas impossible, mais c'est pénible.

Donc, à moins qu'il n'y ait une autre façon d'évaluer ce qui est "mieux", je dirais que la route du bitmask n'est pas aussi bonne que le stockage des permissions dans une structure de base de données normalisée. Je ne suis pas d'accord sur le fait que ce serait "plus lent parce que vous devez faire une jointure" - à moins que vous ayez une base de données totalement dysfonctionnelle, vous ne serez pas en mesure de mesurer cela (alors que l'interrogation sans le bénéfice d'un index actif peut devenir sensiblement plus lente avec même quelques milliers d'enregistrements).

12voto

Oded Points 271275

Personnellement, j'utiliserais un tableau associatif.

Un champ bitmask est très difficile à interroger et à joindre.

Vous pouvez toujours faire correspondre cela à votre enum de drapeaux C# et, si les performances deviennent un problème, remanier la base de données.

La lisibilité prime sur l'optimisation prématurée ;)

5voto

Adam Robinson Points 88472

Stocker les permissions normalisées (c'est-à-dire pas dans un masque de bits). Bien qu'il ne s'agisse évidemment pas d'un exigence pour votre scénario (surtout si les autorisations ne changent pas souvent), cela rendra l'interrogation beaucoup plus facile et plus évidente.

5voto

Aliostad Points 47792

Il y a pas de réponse définitive donc faites ce qui vous convient . Mais voici ma prise :

Utilisez l'option 1 si

  • Vous vous attendez à ce que les permissions augmentent à plusieurs
  • Si vous devez effectuer un contrôle des autorisations dans les procédures stockées de la base de données elle-même
  • Vous n'attendez pas des millions d'utilisateurs, de sorte que les enregistrements dans la table n'augmentent pas massivement.

Utilisez l'option 2 si

  • Les permissions vont être limitées à une poignée
  • Vous attendez des millions d'utilisateurs

1voto

Kevin Points 57797

Le seul cas où j'utiliserais un champ bitmask pour stocker des permissions est celui où la quantité de mémoire physique dont vous disposez est vraiment très limitée.... comme peut-être sur un vieil appareil mobile. En vérité, la quantité de mémoire que vous économisez n'en vaut pas la peine. Même avec des millions d'utilisateurs, l'espace sur le disque dur n'est pas cher, et vous pouvez étendre les autorisations, etc. beaucoup plus facilement en utilisant l'approche non bitmask (il s'agit de faire un rapport sur qui a quelles autorisations, etc.)

L'un des plus gros problèmes que j'ai rencontrés avec ce système est l'attribution de permissions aux utilisateurs directement dans la base de données. Je sais que vous devriez essayer d'utiliser l'application pour s'administrer elle-même et pas trop avec les données de l'application en général, mais parfois, c'est juste nécessaire. A moins que le bitmask ne soit en fait un champ de caractères, et que vous puissiez facilement voir quelles sont les permissions de quelqu'un au lieu d'un nombre entier, essayez d'expliquer à un analyste etc. comment donner un accès en écriture etc. à quelqu'un en mettant à jour le champ..... et priez pour que votre arithmétique soit correcte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X