Vantagens e desvantagens do uso de máscaras de bits no banco de dados

22

Há pouco tempo, conversei com meu colega e ele definitivamente era contra o uso de máscaras de bits, porque é difícil entender todos os valores armazenados no banco de dados. Na minha opinião, nem sempre é uma má idéia usá-los, por exemplo, para determinar os papéis do usuário atual. Caso contrário, você precisará armazená-lo em uma tabela separada, o que causará mais um JOIN. Você pode me dizer se estou errado? Quaisquer outros efeitos colaterais, vantagens / desvantagens do uso de máscaras de bits?

Alex Ovechkin
fonte
2
Pode fazer mais sentido que o banco de dados crie máscaras de bits internamente e apresente os bits como colunas separadas para você. Seus requisitos podem mudar.
22616 Simon Simonter
1
Se você não usa junções, não está usando seu banco de dados relacional da maneira como ele se destina.
Pieter B

Respostas:

38

Trabalho com um aplicativo que usa máscaras para armazenar atribuições de função de usuário. É uma dor no traseiro. Se isso me torna tendencioso, culpado de acusado.

Se você já estiver usando um banco de dados relacional, é um antipadrão que viola a maioria das teorias relacionais e todas as regras de normalização. Quando você cria seu próprio armazenamento de dados, pode não ser uma má idéia.

Há muitas tabelas sendo juntadas, mas bancos de dados relacionais são criados para lidar com isso. Muitos possuem recursos adicionais se o desempenho se tornar um problema: índices, visualizações indexadas etc. Mesmo que os valores que você está pesquisando não sejam alterados com muita frequência, o que é uma vantagem para o Bitmask, a sobrecarga de ter que gerenciar a indexação é bastante fácil no banco de dados.

Embora o banco de dados faça um bom trabalho de agregação de dados, eles podem ficar lentos quando você começa a introduzir coisas como fórmulas complexas ou Funções Escalares nos conjuntos de dados. Você pode fazer o bit a bit no seu aplicativo, mas se tudo o que você está fazendo é obter dados relacionados (procurando as funções de um usuário), não está tirando proveito do que seu armazenamento de dados faz melhor.

Meu último argumento contra isso seria a simplicidade para outros desenvolvedores. Você tem usuários, funções e atribuições. É um conjunto de relações muitos-para-muitos (porque há mais de um relacionamento) que é tão comum que deve ser fácil de gerenciar. São apenas coisas CRUD.

JeffO
fonte
8
Um banco de dados relacional é o pior lugar para uma máscara de bits. Os custos de armazenamento não são mais tão ruins que algumas junções e uma mesa extra devem prejudicá-lo. Certamente torna tudo mais difícil de raciocinar. Armazene as permissões como bits (1/0) no banco de dados em sua própria tabela e represente-as no código com apenas sinalizadores. Parece bastante apropriado e viável. Os desenvolvedores recebem sinalizadores simples e os dbas têm tabelas normalizadas. Todo mundo está feliz.
Mike McMahon
3
Concordo, eu costumava oferecer suporte a um aplicativo que usava máscaras de bits para funções e privilégios de usuário em seu banco de dados. Foi um pesadelo. Usando um int de 32 bits, ficamos sem bits, então alguém teve a ótima idéia de adicionar mais máscaras de bits e, em seguida, com sobreposições, de modo que o bit 4 em uma coluna significou o bit 8 nessa outra coluna e ficou fora de sincronia. Sim, sim, sim. Foi difícil indexar porque os índices armazenam valores de colunas discretos, não os bits individuais neles, portanto, você não pode procurar linhas where some_bit_mask & 12 > 0sem uma verificação linha a linha.
Brandon
No final do dia, uma tabela de muitos para muitos user_role_mapou user_priv_mapseria suficiente.
Brandon
@MikeMcMahon, você poderia se aprofundar no design da tabela e como devo mapeá-la no código para obter o resultado que você está falando?
AlexVechech #
2
@usr - Nunca diga nunca. Claro que você pode usar máscaras de bits, mas eu não as usaria em um aplicativo que usa um banco de dados relacional. Provavelmente existem alguns casos extremos quando se lida com dados herdados ou com uma super necessidade de velocidade.
Jeffo
24

Você já nomeou os prós e contras relevantes:

  • Os campos de bits economizam espaço.
  • Eles armazenam dados no próprio registro, para que você não precise de JOINs para encontrá-los. (Mas campos de sinalizador individuais no registro fariam o mesmo.)
  • Eles são mal legíveis se você deseja trabalhar produtivamente com a saída SQL bruta.

Decidir o que fazer requer mais informações:

  • Quão escasso é o espaço em disco para o seu caso de uso?
  • Você lê as funções de usuário com tanta frequência que o tempo para se juntar a elas é um gargalo?
  • Você vai ler a saída SQL e tomar decisões com base nisso - ou um registro de base de dados ilegível é irrelevante, exatamente como o fato de o código de máquina do seu sistema ser ilegível?

Então, o que você precisa fazer é reunir os fatores de risco e ponderá- los, para ver se os profissionais superam os contras.

Kilian Foth
fonte
Obrigado por sua resposta, concordo totalmente com seus pensamentos, mas em geral isso é anti-padrão ou não? E você usa máscaras em seus projetos?
Alex Ovechkin
12
@ Alex Não existe uma "prática recomendada" que possa decidir o que fazer no seu caso. Se você estiver com pouco espaço, usar os campos de bits é uma prática recomendada. Se você deseja usar a saída SQL em relatórios ao CEO, usar nomes falados é uma prática recomendada. Mas você é o único que conhece essas circunstâncias; portanto, a comunidade não pode lhe dar uma receita sempre válida.
Kilian Foth
Tomando o argumento espacial como um "gimme". A questão de usar uma máscara de bits permanece ou cai sobre se infere algum benefício além disso.
Robbie Dee
Além disso, você TODOS precisam processar as informações no banco de dados ou elas sempre são lidas em um aplicativo antes de usá-lo.
Ian
1
"Você vai ler a saída SQL e tomar decisões com base nisso - ou um registro de base de dados ilegível é irrelevante, exatamente como o fato de o código de máquina do seu sistema ser ilegível?" Acho que não posso falar por todos os desenvolvedores, mas quando estou desenvolvendo, é extremamente comum começar a selecionar dados do banco de dados para entender ou verificar alguma coisa. Então, eu argumentaria que , geralmente , a resposta é: "Sim, alguém o fará".
jpmc26
18

Se você está realmente, realmente , realmente precisando de espaço em disco, então você pode considerar bitmaps para permissões de usuário. Se o desempenho é a sua preocupação, esqueça-os completamente, porque separá-los será mais lento. Você não pode indexar um campo de bitmap significativamente, resultando em varreduras de tabela de banco de dados, que são quase sempre prejudiciais ao desempenho.

A menos que você seja Amazon ou Netflix, a quantidade de dados envolvidos nas permissões de usuário será desprezível em comparação com tudo o que você está mantendo.

Qualquer DBMS sério pode lidar com essa "junção extra" sem sequer piscar.

Phill W.
fonte
7
+1: Os bons bancos de dados relacionais são desenvolvidos por pessoas que são realmente muito, muito boas no que fazem. Qualquer pessoa no nível de necessidade de obter o último desempenho que você pode obter usando campos de bits não precisaria fazer a pergunta. Modele os dados e encontre as partes que não são executadas.
Blrfl
A junção tornará o código do aplicativo mais complexo, portanto, muito se resume a ONDE as funções são processadas.
Ian
4
@Ian ter a associação não parece mais complexo do que precisar saber decifrar as permissões com máscara de bits.
Brad
@ Brad, pense em um enum que é um conjunto de sinalizadores em C #, com seu valor armazenado “como está” no banco de dados, o frio em C # não pode ser mais simples. Se uma junção for usada, o código C # precisará lidar com um relacionamento "1 para muitos".
Ian
Devo acrescentar também que, se você tiver várias colunas booleanas em uma tabela, a maioria dos bancos de dados descobrirá como compactá-las no menor espaço possível e cuidará da manipulação de bits para você.
Blrfl
8

Quando o armazenamento era caro, o benefício com máscaras de bits era que eles economizavam espaço. Nos dias de big data, esse não era o problema que era antes.

Tomando o exemplo que você cita - ter funções armazenadas como uma máscara de bits seria uma espécie de cheiro de código do ponto de vista do design do banco de dados, pois violaria a primeira forma normal . Nesse sentido, eles são um anti-padrão.

Tudo isso dito, não precisa ser um ou outro. Você pode armazenar os dados como uma máscara de bits e, em seguida, ter uma visão que possa puxar as funções de usuário rapidamente. Você também terá o benefício de verificar rapidamente quais usuários têm as mesmas funções.

Robbie Dee
fonte
2

A única vantagem do uso de máscaras de bits é se o significado dos campos de bits não for estático. As tabelas relacionais só funcionam bem se você souber com antecedência o que cada campo está em um registro: CREATE TABLEafinal, é necessário identificar os campos na instrução DDL.

Se o significado de cada campo de bits for configurável no tempo de execução ou não for conhecido antecipadamente, poderá fazer sentido armazenar booleanos como um campo de bits. Mesmo assim, é possível definir uma tabela com campos arbitrários: field_1, field_2, etc. Isto dá-lhe um design relacional mais limpo, embora ainda não ideal. Se isso é preferencial a um campo de bits, é em grande parte uma questão de opinião, pois nenhuma solução é ideal.

Se você souber o que os bits representam durante o desenvolvimento, crie campos para cada bit e atribua nomes significativos .

Apenas tome cuidado com o efeito da plataforma interna . Se você acabar definindo campos arbitrários, mas bem digitados, isso é uma coisa, mas se você for muito além, reinventará um banco de dados relacional ... dentro de um banco de dados relacional.


fonte
2

Eu sou ambivalente sobre máscaras de bits. Acho que a maioria de seus detratores não entende binário e hexadecimal. Para maior clareza, use boas mnemônicas.

Uma vantagem não mencionada acima é a capacidade de adicionar novo significado às máscaras de bits sem a adição potencialmente demorada de uma nova coluna. Nossos designers de banco de dados (que me precederam) os colocam em uma tabela que agora recebe 5 milhões de novos registros diariamente. Adicionar uma nova coluna para representar um novo comportamento levaria muito tempo, enquanto definir um novo bit (consumimos 33 de 64) não requer reconstrução da tabela.

Não, as máscaras de bits não podem ser indexadas, mas criar 33 índices seria ridículo e atrasaria as inserções em um rastreamento. As pesquisas de tabela usam os índices "proprietários" de datas e registros; portanto, os índices nessa máscara de bits, se possível, nunca seriam usados.

GB
fonte
É um caso interessante. Suponho que você possa conseguir o mesmo de uma maneira kosher e explícita, definindo colunas "sobressalentes" na tabela e, em seguida, colocando-as em uso conforme necessário. Você pode, pelo menos, indexar essas colunas seletivamente, caso opte por fazê-lo.
Steve
1

Se o objetivo é apenas economizar espaço em disco, acho uma má ideia:

  • veja o custo do GB hoje,
  • compará-lo com o custo do tempo de quem escreve relatórios e consultas e precisa descobrir o que há no campo e como lidar com um bit específico, a comparação de custo / benefício pode terminar do lado errado.
  • se você estiver trabalhando com um banco de dados SQL, as operações adicionais de acesso a bits necessárias em muitas consultas também poderão consumir mais tempo de computação do que o necessário

No entanto, existem alguns casos que podem justificar o uso de campos de bits:

  • se seus bits representam um conjunto complexo de sinalizadores que você sempre manipula como um todo,
  • ainda mais se você precisar aplicar alguns algoritmos de correspondência de padrões nesses conjuntos,
  • e especialmente se esses dados não estiverem entre os critérios de seleção mais frequentemente usados.
Christophe
fonte