Avantages et inconvénients de l'utilisation de masques de bits dans la base de données

22

Il n'y a pas si longtemps, j'ai parlé à mon collègue et il était définitivement contre l'utilisation de masques de bits car il est difficile de comprendre toutes les valeurs stockées dans la base de données. À mon avis, ce n'est pas toujours une mauvaise idée de les utiliser, par exemple pour déterminer les rôles de l'utilisateur actuel. Sinon, vous devez le stocker dans une table distincte, ce qui entraînera une autre JOIN. Pouvez-vous me dire si je me trompe? Y a-t-il d'autres effets secondaires, avantages / inconvénients de l'utilisation de masques de bits?

Alex Ovechkin
la source
2
Il peut être plus judicieux que la base de données crée des masques de bits en interne et vous présente les bits sous forme de colonnes distinctes. Vos exigences peuvent changer.
Simon Richter
1
Si vous n'utilisez pas de jointures, vous n'utilisez pas votre base de données relationnelle comme prévu.
Pieter B

Réponses:

38

Je travaille avec une application qui utilise des masques de bit pour stocker les attributions de rôles utilisateur. C'est une douleur dans le cul. Si cela me rend partial, coupable comme accusé.

Si vous utilisez déjà une base de données relationnelle, il s'agit d'un anti-modèle qui viole la plupart des théories relationnelles et toutes les règles de normalisation. Lorsque vous créez votre propre stockage de données, ce n'est peut-être pas une si mauvaise idée.

Il y a une telle chose que trop de tables sont jointes, mais des bases de données relationnelles sont construites pour gérer cela. Beaucoup ont des fonctionnalités supplémentaires si les performances deviennent un problème: index, vues indexées, etc. Même si les valeurs que vous recherchez ne changent pas très souvent, ce qui est un avantage pour Bitmask, la surcharge de gestion de l'indexation est assez facile sur la base de données.

Bien que la base de données fasse un bon travail d'agrégation de données, elles peuvent devenir lentes lorsque vous commencez à introduire des choses comme des formules complexes ou des fonctions scalaires dans des ensembles de données. Vous pouvez le faire au niveau du bit dans votre application, mais si tout ce que vous faites est d'obtenir des données connexes (rechercher les rôles d'un utilisateur), vous ne profitez pas de ce que votre stockage de données fait de mieux.

Mon dernier argument contre cela serait la simplicité pour les autres développeurs. Vous avez des utilisateurs, des rôles et des affectations. C'est un ensemble de relations plusieurs-à-plusieurs (car il y a plus d'une relation) qui est si commun qu'il devrait être facile à gérer. C'est juste des trucs CRUD.

JeffO
la source
8
Une base de données relationnelle est le pire endroit pour un masque de bits. Les coûts de stockage ne sont plus si mauvais que quelques jointures et une table supplémentaire devraient vous briser. Cela rend certainement tout plus difficile à raisonner. Stockez les autorisations sous forme de bits (1/0) dans la base de données dans leur propre table et représentez-les dans le code avec des indicateurs mais. Semble assez approprié et faisable. Les développeurs obtiennent des indicateurs simples et les dbas ont des tables normalisées. Tout le monde est content.
Mike McMahon
3
D'accord, j'avais l'habitude de prendre en charge une application qui utilisait des masques de bits pour les rôles et privilèges utilisateur dans sa base de données. C'était un cauchemar. En utilisant un entier 32 bits, nous avons manqué de bits, donc quelqu'un a eu la bonne idée d'ajouter plus de masques de bits, puis avec des chevauchements, donc le bit 4 dans une colonne signifiait le bit 8 dans cette autre colonne, et ils se sont désynchronisés. Aye aye aye. Il était difficile d'indexer, car les index stockent des valeurs de colonne discrètes, pas les bits individuels qu'elles contiennent, vous ne pouvez donc pas rechercher des lignes where some_bit_mask & 12 > 0sans un balayage ligne par ligne.
Brandon
A la fin de la journée, un grand nombre à plusieurs user_role_mapou la user_priv_maptable aurait suffi.
Brandon
@MikeMcMahon, pourriez-vous s'il vous plaît plonger plus profondément dans la conception des tableaux et comment dois-je le mapper dans le code afin d'obtenir le résultat dont vous parlez?
Alex Ovechkin
2
@usr - Ne dites jamais jamais. Bien sûr, vous pouvez utiliser des bitmasks, mais je ne les utiliserais pas dans une application qui utilise une base de données relationnelle. Il existe probablement des cas marginaux lorsqu'il s'agit de données héritées ou d'un super besoin de vitesse.
JeffO
24

Vous avez déjà nommé les avantages et les inconvénients pertinents:

  • Les champs de bits économisent de l'espace.
  • Ils stockent des données dans l'enregistrement lui-même, vous n'avez donc pas besoin de JOIN pour les trouver. (Mais les champs d'indicateur individuels de l'enregistrement feraient de même.)
  • Ils sont mal lisibles si vous souhaitez travailler de manière productive avec une sortie SQL brute.

Décider quoi faire nécessite plus d'informations:

  • À quel point l'espace disque est-il limité pour votre cas d'utilisation?
  • Lisez-vous réellement les rôles des utilisateurs si souvent que le temps de les rejoindre est un goulot d'étranglement?
  • Allez- vous lire la sortie SQL et prendre des décisions en fonction de cela - ou un enregistrement de base de données illisible est-il immatériel, tout comme le fait que le code machine de votre système est illisible?

Donc, ce que vous devez faire est de rassembler les facteurs de risque, puis de les pondérer , pour voir si les avantages l'emportent sur les inconvénients.

Kilian Foth
la source
Merci pour votre réponse, totalement d'accord avec vos réflexions, mais en général est-ce anti-pattern ou pas? Et utilisez-vous des masques dans vos projets?
Alex Ovechkin
12
@Alex Il n'existe pas de "meilleure pratique" qui puisse décider quoi faire dans votre cas. Si vous manquez d'espace, l'utilisation de champs de bits est la meilleure pratique. Si vous souhaitez utiliser la sortie SQL dans les rapports au PDG, l'utilisation de noms parlants est la meilleure pratique. Mais vous êtes le seul à connaître ces circonstances, la communauté ne peut donc pas vous donner une prescription toujours valable.
Kilian Foth
Prenant l'argument de l'espace comme un "gimme". La question de savoir s'il faut utiliser un masque de bits se pose ou tombe sur s'il en déduit un avantage en plus.
Robbie Dee
De plus, avez-vous CHAQUE besoin de traiter les informations dans la base de données, ou est-ce toujours lu dans une application avant de l'utiliser?
Ian
1
"Allez-vous lire la sortie SQL et prendre des décisions en fonction de cela - ou un enregistrement de base de données illisible est-il immatériel, tout comme le fait que le code machine de votre système est illisible?" Je suppose que je ne peux pas parler pour tous les développeurs, mais lorsque je développe, il est extrêmement courant que je commence à sélectionner des données dans la base de données pour comprendre ou vérifier quelque chose. Je dirais donc qu'en général , la réponse à cette question est: "Oui, quelqu'un le fera."
jpmc26
18

Si vous êtes vraiment, vraiment , vraiment à court d'espace disque, vous pouvez envisager des bitmaps pour les autorisations utilisateur. Si les performances vous inquiètent, oubliez-les complètement, car les séparer sera en fait plus lent. Vous ne pouvez pas indexer un champ bitmap de manière significative, ce qui entraîne des analyses de table de base de données, qui sont [presque] toujours un tueur de performances.

À moins que vous ne soyez Amazon ou Netflix, la quantité de données impliquées dans les autorisations utilisateur sera négligeable par rapport à tout ce que vous détenez.

Tout SGBD sérieux peut gérer cette "jointure supplémentaire" sans même clignoter.

Phill W.
la source
7
+1: Les bonnes bases de données relationnelles sont développées par des gens qui sont vraiment, vraiment, vraiment bons dans ce qu'ils font. N'importe qui au niveau d'avoir besoin d'extraire le dernier bit de performance que vous pourriez obtenir en utilisant des champs de bits n'aurait pas besoin de poser la question. Modélisez les données, puis recherchez les pièces qui ne fonctionnent pas.
Blrfl
La jointure rendra le code de l'application plus complexe, donc tout dépend de OERE les rôles sont traités.
Ian
4
@Ian ayant la jointure ne semble pas plus complexe que de savoir comment déchiffrer les autorisations masquées par bits.
Brad
@Brad, Pensez à une énumération qui est un ensemble d'indicateurs en C #, avec sa valeur stockée «telle quelle» dans la base de données, le froid C # ne peut pas être plus simple. Si une jointure est utilisée, le code C # doit faire face à une relation «1 à plusieurs».
Ian
Je dois également ajouter que si vous avez plusieurs colonnes booléennes dans une table, la plupart des bases de données trouveront comment les écraser dans le moins d'espace possible et s'occuperont du bit-twiddling pour vous.
Blrfl
8

À l'époque où le stockage était cher, l'avantage des masques à mors était qu'ils avaient économisé de l'espace. À l'époque du Big Data, ce n'était plus le problème.

Prenons l'exemple que vous citez - avoir des rôles stockés sous forme de masque de bits serait une sorte d'odeur de code du point de vue de la conception d'une base de données car il violerait la première forme normale . En ce sens, ils sont anti-modèle.

Cela étant dit, il n'est pas nécessaire que ce soit l'un ou l'autre. Vous pouvez stocker les données sous forme de masque de bits, puis avoir une vue qui peut extraire les rôles d'utilisateur à la volée. Vous auriez également l'avantage de vérifier en un coup d'œil quels utilisateurs avaient les mêmes rôles.

Robbie Dee
la source
2

Le seul avantage de l'utilisation des masques de bits est que la signification des champs de bits n'est pas statique. Les tables relationnelles ne fonctionnent bien que si vous savez à l'avance ce que chaque champ est sur un enregistrement: vous devez après tout identifier les champs dans l' CREATE TABLEinstruction DDL.

Si la signification de chaque champ de bits est configurable au moment de l'exécution, ou autrement inconnue à l'avance, il peut être judicieux de stocker les booléens en tant que champ de bits. Même alors, il est possible de définir une table avec des champs arbitraires: field_1, field_2, etc. Cela vous donne une conception relationnelle plus propre, mais toujours pas idéal. Que ce soit préférentiel à un champ de bits est en grande partie une question d'opinion, car aucune solution n'est idéale.

Si vous savez ce que les bits représentent pendant le développement, créez des champs pour chaque bit et donnez-leur des noms significatifs .

Faites juste attention à l' effet de plateforme interne . Si vous finissez par définir des champs arbitraires mais bien typés, c'est une chose, mais si vous allez trop loin, vous réinventerez une base de données relationnelle ... à l'intérieur d'une base de données relationnelle.


la source
2

Je suis ambivalent au sujet des bitmasks. Je trouve que la plupart de leurs détracteurs ne comprennent pas le binaire et l'hexadécimal. Pour plus de clarté, utilisez de bons mnémoniques.

Un avantage non mentionné ci-dessus est la possibilité d'ajouter une nouvelle signification aux masques de bits sans l'ajout potentiellement long d'une nouvelle colonne. Nos concepteurs de base de données (qui m'ont précédé) les ont dans un tableau qui obtient maintenant 5 millions de nouveaux enregistrements par jour. L'ajout d'une nouvelle colonne pour représenter un nouveau comportement prendrait beaucoup de temps, tandis que la définition d'un nouveau bit (nous en avons consommé 33 sur 64) ne nécessite aucune reconstruction de table.

Non, les masques de bits ne peuvent pas être indexés, mais la création de 33 index serait ridicule et ralentirait les insertions dans une analyse. Les recherches de table utilisent les dates et enregistrent les index "propriétaires", donc les index sur ce masque de bits, si possible, ne seront jamais utilisés.

GB
la source
C'est un cas intéressant. Je suppose que vous pourriez obtenir le même résultat de manière casher et explicite, en définissant des colonnes "de rechange" sur la table, puis en les mettant en service selon vos besoins. Vous pouvez ensuite au moins indexer ces colonnes de manière sélective, si vous le souhaitez.
Steve
1

Si le but est juste d'économiser de l'espace disque, je pense que c'est une mauvaise idée:

  • regardez le coût du GB aujourd'hui,
  • le comparer au coût du temps de ceux qui rédigent des rapports et des requêtes et doivent comprendre ce qui se trouve sur le terrain, et comment traiter un bit spécifique, la comparaison coût / avantage pourrait se terminer du mauvais côté.
  • si vous travaillez avec une base de données SQL, les opérations supplémentaires d'accès aux bits requises dans de nombreuses requêtes peuvent également consommer plus de temps de calcul que nécessaire

Cependant, il existe certains cas, qui peuvent justifier l'utilisation de champs de bits:

  • si vos bits représentent un ensemble complexe de drapeaux que vous gérez toujours ensemble dans leur ensemble,
  • encore plus si vous devez appliquer des algorithmes de correspondance de motifs sur ces ensembles,
  • et surtout si ces données ne figurent pas parmi les critères de sélection les plus fréquemment utilisés.
Christophe
la source