Banco de dados de valor de atributo da entidade vs. comércio eletrônico estrito do modelo relacional

136

É seguro dizer que o modelo de banco de dados EAV / CR é ruim. Dito isto,

Pergunta: Que modelo, técnica ou padrão de banco de dados deve ser usado para lidar com "classes" de atributos que descrevem produtos de comércio eletrônico que podem ser alterados em tempo de execução?

Em um bom banco de dados de comércio eletrônico, você armazenará classes de opções (como resolução de TV e, em seguida, uma resolução para cada TV, mas o próximo produto pode não ser uma TV e não ter "resolução de TV"). Como você os armazena, pesquisa com eficiência e permite que seus usuários configurem tipos de produtos com campos variáveis ​​que descrevem seus produtos? Se o mecanismo de pesquisa descobrir que os clientes geralmente pesquisam TVs com base na profundidade do console, você pode adicionar a profundidade do console aos seus campos e adicionar uma profundidade única para cada tipo de produto de TV em tempo de execução.

Há um bom recurso comum entre os bons aplicativos de comércio eletrônico, nos quais eles mostram um conjunto de produtos e, em seguida, têm menus laterais "detalhados", nos quais é possível ver "Resolução da TV" como um cabeçalho e as cinco principais resoluções de TV mais comuns para o conjunto encontrado. Você clica em um e ele mostra apenas TVs com essa resolução, permitindo aprofundar a seleção, selecionando outras categorias no menu lateral. Essas opções seriam os atributos dinâmicos do produto adicionados no tempo de execução.

Discussão adicional:

Para encurtar a história, existem links na Internet ou descrições de modelos que possam "academicamente" corrigir a seguinte configuração? Agradeço a Noel Kennedy por sugerir uma tabela de categorias, mas a necessidade pode ser maior que isso. Descrevo-o de uma maneira diferente abaixo, tentando destacar o significado. Talvez eu precise de uma correção de ponto de vista para resolver o problema, ou talvez precise aprofundar o EAV / CR.

Adore a resposta positiva ao modelo EAV / CR. Meus colegas desenvolvedores dizem o que Jeffrey Kemp abordou abaixo: "novas entidades devem ser modeladas e projetadas por um profissional" (fora do contexto, leia sua resposta abaixo). O problema é:

  • entidades adicionam e removem atributos semanalmente
    (as palavras-chave de pesquisa determinam atributos futuros)
  • novas entidades chegam semanalmente
    (os produtos são montados a partir de peças)
  • entidades antigas desaparecem semanalmente
    (arquivadas, menos populares, sazonais)

O cliente deseja adicionar atributos aos produtos por dois motivos:

  • departamento / pesquisa de palavras-chave / gráfico de comparação entre produtos similares
  • configuração do produto de consumo antes da finalização da compra

Os atributos devem ter significado, não apenas uma pesquisa por palavra-chave. Se eles quiserem comparar todos os bolos com "glacê de chantilly", eles podem clicar em bolos, clicar no tema do aniversário, clicar em glacê de chantilly e verificar todos os bolos que são interessantes, sabendo que todos têm glacê de chantilly. Isso não é específico para bolos, apenas um exemplo.

Zachary Scott
fonte
Por que você não pode simplesmente ter uma tabela 'categoria' com uma chave estrangeira referente a si mesma?
2029 Noel Kennedy
29
Não é seguro nem preciso dizer que o modelo de banco de dados EAV é ruim, porque é adequado para alguns aplicativos.
Spencer7593 15/05/09
E se você decorar vários objetos com várias propriedades, herdando de um pai como no Entity Framework 4? Como persiste esses objetos?
Zachary Scott
1
Volte ao ponto deste excelente artigo sobre a experiência de um consultor em um sistema baseado em uma versão extrema do EAV. Leia-o! simple-talk.com/opinion/opinion-pieces/bad-carma
Jeffrey Kemp
1
O EAV é um modelo de banco de dados muito viável. Estou trabalhando em um problema semelhante ao seu e a solução é EAV. Eu recomendaria o seguinte artigo: sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/…
Sandor

Respostas:

75

Existem alguns prós e contras gerais em que consigo pensar, há situações em que uma é melhor que a outra:

Opção 1, modelo EAV:

  • Pro: menos tempo para projetar e desenvolver um aplicativo simples
  • Pro: novas entidades fáceis de adicionar (podem até ser adicionadas pelos usuários?)
  • Pro: componentes de interface "genéricos"
  • Con: código complexo necessário para validar tipos de dados simples
  • Con: SQL muito mais complexo para relatórios simples
  • Contras: relatórios complexos podem se tornar quase impossíveis
  • Con: baixo desempenho para grandes conjuntos de dados

Opção 2, Modelando cada entidade separadamente:

  • Con: mais tempo necessário para reunir requisitos e design
  • Con: novas entidades devem ser modeladas e projetadas por um profissional
  • Con: componentes de interface personalizados para cada entidade
  • Pro: restrições e validação de tipo de dados simples de implementar
  • Pro: SQL é fácil de escrever, fácil de entender e depurar
  • Pro: até os relatórios mais complexos são relativamente simples
  • Pro: melhor desempenho para grandes conjuntos de dados

Opção 3, combinação (entidades de modelo "corretamente", mas adicione "extensões" para atributos personalizados para algumas / todas as entidades)

  • Pro / Con: mais tempo necessário para reunir requisitos e design do que a opção 1, mas talvez não tanto quanto a opção 2 *
  • Con: novas entidades devem ser modeladas e projetadas por um profissional
  • Pro: novos atributos podem ser facilmente adicionados posteriormente
  • Con: código complexo necessário para validar tipos de dados simples (para os atributos personalizados)
  • Con: componentes de interface personalizados ainda são necessários, mas componentes de interface genéricos podem ser possíveis para os atributos personalizados
  • Con: SQL se torna complexo assim que qualquer atributo personalizado é incluído em um relatório
  • Con: bom desempenho em geral, a menos que você comece a precisar pesquisar ou reportar pelos atributos personalizados

* Não tenho certeza se a opção 3 necessariamente pouparia algum tempo na fase de design.

Pessoalmente, eu me inclinaria para a opção 2 e evitaria o EAV sempre que possível. No entanto, para alguns cenários, os usuários precisam da flexibilidade que acompanha o EAV; mas isso tem um ótimo custo.

Jeffrey Kemp
fonte
E se você tivesse uma única tabela com índices para os valores de texto 1-n, em C # (em memória ram) mapeie o que deseja para o que precisa. Ainda funcionaria como um EAV, mas as "correspondências" seriam modelos de domínio. É como uma serialização, mas você pode usar seleções SQL em campos de texto indexados. Não há várias seleções por registro. Todo o "custo" acontece na RAM.
Zachary Scott
1
@Zim, isso parece muito com a opção 3. Cada linha possui 1-n colunas "genéricas" extras, e os dados armazenados nelas são interpretados no nível do aplicativo. Você obtém o benefício de desempenho de ter todos os dados para um registro em um só lugar. Os metadados sobre essas colunas precisam ser armazenados em algum lugar, no entanto, e é aí que o custo se aproxima. Certamente, podemos armazenar em cache os metadados no RAM, mas ainda custa mais do que ter o domínio modelado diretamente no código do aplicativo. Certamente melhor do que um modelo EAV completo!
Jeffrey Kemp
1
+10000 Ótima resposta. Atualmente, as pessoas economizam no design de banco de dados e na coleta de requisitos. Eles preferem escrever centenas de vezes mais linhas de código, que levam tempo para criar um bom design.
Tulains Córdova
Você não precisa de mais design para a opção relacional (2) do que a opção EAV (1) se estiver fornecendo apenas a estrutura da opção 1. E a interface relacional é genérica a partir dos metadados que descrevem essa estrutura. Isso remove todas as opções 2 Contras. No entanto, você esqueceu que o único Con: DDL real pode ser muito lento para gerenciar tabelas.
philipxy
Oi @ philipxy, eu não disse "mais design". A razão de ser do EAV é que (presumivelmente) o projetista do sistema pode gastar menos tempo projetando o modelo, deixando esse trabalho de design para os "usuários" posteriormente (essa falta de design profissional leva aos Contras listados na Opção 1) . Se o EAV não gerar economia para o projetista, isso só adiciona mais combustível ao incêndio por rejeitar o EAV imediatamente. Além disso, eu discordo que o DDL é "muito lento" - uma vez que só deve ser exigido raramente (ou seja, para corrigir erros no modelo ou implementar novos recursos), seu desempenho deve ser relativamente sem importância.
Jeffrey Kemp
63

É seguro dizer que o modelo de banco de dados EAV / CR é ruim.

Não, não é. Só que eles são um uso ineficiente de bancos de dados relacionais. Uma loja puramente de chave / valor funciona muito bem com este modelo.

Agora, para sua verdadeira pergunta: como armazenar vários atributos e mantê-los pesquisáveis?

Basta usar o EAV. No seu caso, seria uma única mesa extra. indexá-lo no nome e no valor do atributo, a maioria dos RDBMs usaria compactação de prefixo nas repetições de nomes de atributos, tornando-o realmente rápido e compacto.

O EAV / CR fica feio quando você o usa para substituir os campos 'reais'. Como em todas as ferramentas, o uso excessivo é "ruim" e gera uma imagem ruim.

Javier
fonte
então a questão é que eu tenho 15 campos adicionais para uma das minhas categorias e no modelo eav requer 16 join + tabela principal, tornando 16 restantes à procura de produtos (e tendo 16 onde o cliente deseja) em 3-4 milhões de registros ( um site para vender produtos em segunda mão por pessoas), para que o desempenho seja baixo?
Babak faghihian
2
Se esses "campos adicionais" já estiverem definidos, seria melhor fazê-lo como "campos reais". E, é claro, fazer um número ilimitado de junções em uma consulta grande seria um pedágio pesado (mas ainda pode ser bom!). O que eu fiz em um projeto pesado de metadados é permitir qualquer número de "tags" (como registros EAV) por "item principal", mas a "consulta grande" seleciona apenas alguns nomes de tag predefinidos, mantendo limitado o número total de junções (atualmente típico está apenas a 4 tags e cerca de 5 outras associações), e quando o usuário seleciona um item específico, em seguida, ele fetchs tudo relacionado, mas para um único item.
Javier
mas é claro, que o sistema específico está sendo portado para um hstorecampo (apenas uma das razões pelas quais usar o PostgreSQL)
Javier
15
// Neste momento, gostaria de falar um pouco sobre o formato Magento / Adobe PSD .
// Magento / PSD não é uma boa plataforma / formato de comércio eletrônico . Magento / PSD nem sequer é uma plataforma / formato de comércio eletrônico ruim . Chamá-lo assim seria um
// insulta outros formatos / plataformas de comércio eletrônico ruins , como Zencart ou OsCommerce. Não, o Magento / PSD é uma plataforma / formato de comércio eletrônico péssimo . Tendo
// trabalhei nesse código há várias semanas, meu ódio pelo Magento / PSD se tornou um fogo furioso
// que queima com a feroz paixão de um milhão de sóis.

http://code.google.com/p/xee/source/browse/trunk/XeePhotoshopLoader.m?spec=svn28&r=11#107

Os modelos internos são malucos, na melhor das hipóteses, como alguém colocar o esquema em um jogo de boggle, selá-lo e colocá-lo em um shacker de tinta ...

Mundo real: estou trabalhando em um aplicativo de atendimento de midware e aqui estão uma das consultas para obter informações de endereço.

CREATE OR REPLACE VIEW sales_flat_addresses AS
SELECT sales_order_entity.parent_id AS order_id, 
       sales_order_entity.entity_id, 
       CONCAT(CONCAT(UCASE(MID(sales_order_entity_varchar.value,1,1)),MID(sales_order_entity_varchar.value,2)), "Address") as type, 
       GROUP_CONCAT( 
         CONCAT( eav_attribute.attribute_code," ::::: ", sales_order_entity_varchar.value )
         ORDER BY sales_order_entity_varchar.value DESC
         SEPARATOR '!!!!!' 
       ) as data
  FROM sales_order_entity
       INNER JOIN sales_order_entity_varchar ON sales_order_entity_varchar.entity_id = sales_order_entity.entity_id
       INNER JOIN eav_attribute ON eav_attribute.attribute_id = sales_order_entity_varchar.attribute_id
   AND sales_order_entity.entity_type_id =12
 GROUP BY sales_order_entity.entity_id
 ORDER BY eav_attribute.attribute_code = 'address_type'

Extrai informações de endereço de um pedido, preguiçosamente

-

Resumo: Use o Magento apenas se:

  1. Você está recebendo grandes sacos de dinheiro
  2. Você deve
  3. Aproveite a dor
Vee
fonte
Este é um post antigo, mas eu gostaria de ter encontrado isso há 3 meses quando iniciei um projeto Magento para um cliente. +1 para a analogia boggle / shaker-paint!
trevorc
1
Bastante interessante, o magento parece ser o rei da estrada em termos de sistemas de comércio eletrônico. Talvez apenas o marketing seja muito bom
Herr
1
O Magento não é popular por causa do nível de manutenção, mas da capacidade de personalizar, permitindo a qualquer pessoa implementar novos recursos sem alterações na arquitetura ou poucas modificações. Esse recurso tem um custo.
Diego Mendes
Fique longe de Magento 2 se você quer evitar Triplo dor e mais dor na parte superior para ambos FE e BE
TheBlackBenzKid
15

Estou surpreso que ninguém tenha mencionado os bancos de dados NoSQL.

Nunca pratiquei o NoSQL em um contexto de produção (acabei de testar o MongoDB e fiquei impressionado), mas o objetivo principal do NoSQL é poder salvar itens com atributos variados no mesmo "documento".

Lucas T
fonte
Considere que as gravações no MongoDB exigem bloqueio no nível do banco de dados e o que isso significa para o tráfego de produção simultâneo.
Bill Karwin
Considere que a duração do bloqueio é da ordem de microssegundos.
Olá Mundo
12

Onde o desempenho não é um requisito importante, como em um tipo de aplicativo ETL, o EAV tem outra vantagem distinta: economia de diferencial.

Eu implementei um número de aplicativos em que um requisito abrangente era a capacidade de ver o histórico de um objeto de domínio desde sua primeira "versão" até seu estado atual. Se esse objeto de domínio tiver um grande número de atributos, isso significa que cada alteração exige que uma nova linha seja inserida em sua tabela correspondente (não uma atualização porque o histórico seria perdido, mas uma inserção). Digamos que esse objeto de domínio seja uma Pessoa, e eu tenho 500 mil Pessoas para rastrear com uma média de mais de 100 alterações ao longo do ciclo de vida de Pessoas em vários atributos. Associe isso ao fato de que raro é o aplicativo que possui apenas um objeto de domínio principal e você rapidamente pressupõe que o tamanho do banco de dados crescerá rapidamente fora de controle.

Uma solução fácil é salvar apenas as alterações diferenciais nos principais objetos do domínio, em vez de salvar repetidamente informações redundantes.

Todos os modelos mudam ao longo do tempo para refletir novas necessidades de negócios. Período. Usar o EAV é apenas uma das ferramentas em nossa caixa para usar; mas nunca deve ser automaticamente classificado como "ruim".

Jerry Jasperson
fonte
2
O +1 em "Usar o EAV é apenas uma das ferramentas em nossa caixa para uso; mas nunca deve ser automaticamente classificado como" ruim "".
Catchops
Btw, isso é chamado de SCD (dimensões que mudam lentamente). Os requisitos bitemporais (um caso específico do SCD Tipo 4) também exigem esquema EAV para os atributos que possuem essa propriedade. Lembre-se, 99% do NoSQL não possui junções nativas; portanto, se você precisar de junções "ao vivo" com esse tipo de dados, o EAV é o único caminho a percorrer.
cowbert
3

Estou lutando com o mesmo problema. Pode ser interessante verificar a seguinte discussão sobre duas soluções de comércio eletrônico existentes: Magento (EAV) e Joomla (estrutura relacional regular): https://forum.virtuemart.net/index.php?topic=58686.0

Parece que o desempenho de EAV do Magento é um verdadeiro empecilho.

É por isso que estou inclinado a uma estrutura normalizada. Para superar a falta de flexibilidade, estou pensando em adicionar um dicionário de dados separado no futuro (XML ou tabelas de banco de dados separadas) que possam ser editados e, com base nisso, o código do aplicativo para exibir e comparar categorias de produtos com novos atributos seria gerado, juntamente com scripts SQL.

Essa arquitetura parece ser o ponto mais interessante nesse caso - flexível e com bom desempenho ao mesmo tempo.

O problema pode ser o uso frequente de ALTER TABLE em ambiente ativo. Estou usando o Postgres, portanto, esperamos que seu MVCC e DDL transacional aliviem a dor.

aaimnr
fonte
2

Ainda voto na modelagem no nível atômico de menor significado para o EAV. Permita que padrões, tecnologias e aplicativos voltados para determinada comunidade de usuários decidam modelos de conteúdo, necessidades de repetição de atributos, grãos, etc.

Amanda Xu
fonte
2

Se se trata apenas dos atributos do catálogo de produtos e, portanto, os requisitos de validação para esses atributos são bastante limitados, a única desvantagem real do EAV é o desempenho da consulta e isso é apenas um problema quando sua consulta lida com várias "coisas" (produtos) com atributos, o desempenho da consulta "fornece todos os atributos para o produto com o ID 234", embora não seja o ideal, ainda é bastante rápido.

Uma solução é usar o modelo de banco de dados SQL / EAV apenas para o lado admin / edit do catálogo de produtos e ter algum processo que desnormalize os produtos em algo que o torne pesquisável. Como você já possui atributos e, portanto, é bem provável que deseje facetas, isso pode ser Solr ou ElasticSearch. Essa abordagem evita basicamente todas as desvantagens do modelo EAV e a complexidade adicionada é limitada à serialização de um produto completo para o JSON na atualização.

prumo
fonte
2

O EAV tem muitos inconvenientes:

  1. Degradação do desempenho ao longo do tempo Depois que a quantidade de dados no aplicativo cresce além de um determinado tamanho, é provável que a recuperação e a manipulação desses dados se tornem cada vez menos eficientes.
  2. As consultas SQL são muito complexas e difíceis de escrever.
  3. Problemas de integridade de dados. Você não pode definir chaves estrangeiras para todos os campos necessários.
  4. Você precisa definir e manter seus próprios metadados.
Gabriel Voinea
fonte
1. Isso também é verdadeiro para a maioria dos bancos de dados relacionais; é por isso que o sharding foi inventado. 2. A modelagem de dados pode ser complexa e difícil de implementar. Passei semanas e meses aguardando alterações no esquema do cubo OLAP. 3. Já é feito principalmente em software agora. 4. Você precisa fazer isso "no ERwin, Excel e Visio" ao modelar um esquema relacional de qualquer maneira.
cowbert
1

Eu tenho um problema um pouco diferente: em vez de muitos atributos com valores esparsos (que é possivelmente um bom motivo para usar o EAV), quero armazenar algo mais como uma planilha. As colunas na planilha podem mudar, mas dentro de uma planilha todas as células conterão dados (não esparsos).

Fiz um pequeno conjunto de testes para comparar dois projetos: um usando EAV e outro usando o Postgres ARRAY para armazenar dados de células.

EAV insira a descrição da imagem aqui

Matriz insira a descrição da imagem aqui

Ambos os esquemas têm índices nas colunas apropriadas e os índices são usados ​​pelo planejador.

Descobriu -se que o esquema baseado em matriz era uma ordem de magnitude mais rápida para inserções e consultas. A partir de testes rápidos, parecia que ambos eram dimensionados linearmente. Os testes não são muito completos, no entanto. Sugestões e garfos são bem-vindos - eles estão sob uma licença do MIT.

z0r
fonte
como você se uniu nas colunas da planilha (ou seja, vlookup) com o modelo de matriz? Você não precisa escrever sua própria função de classificação de mesclagem de matriz? É altamente duvidoso que pode ser tão bom quanto a classificação de mesclagem pré-compilada se você usou sheet_id + coordenada x + coordenada y de uma célula como a chave do valor da célula. (para emular o Excel, gere uma tabela de pesquisa para as coordenadas x, onde 0-18278 são as colunas A-ZZZ (excel atinge o máximo em 16384)), então você pode selecionar valores em que sheet_id = uuid ex-coord = 0 e y-coord <1,001 para obter primeiras 1.000 linhas de col A.
cowbert
@cowbert você está certo; na verdade, apenas carrego as colunas nas quais estou interessado e faço a junção no Python. Slack!
Z0r 13/07/19