Suponha que eu esteja criando um blog que eu queira ter postagens e comentários. Portanto, crio duas tabelas, uma tabela 'posts' com uma coluna 'id' de número inteiro automático e uma tabela 'comments' que possui uma chave estrangeira 'post_id'.
Quero executar o que provavelmente será minha consulta mais comum, que é recuperar uma postagem e todos os seus comentários. Sendo uma novidade para os bancos de dados relacionais, a abordagem que me parece mais óbvia é escrever uma consulta que se pareça com:
SELECT id, content, (SELECT * FROM comments WHERE post_id = 7) AS comments
FROM posts
WHERE id = 7
O que me daria o ID e o conteúdo da postagem que eu quero, juntamente com todas as linhas de comentários relevantes empacotadas ordenadamente em uma matriz (uma representação aninhada como você usaria no JSON). É claro que os bancos de dados SQL e relacionais não funcionam assim, e o mais próximo que eles podem chegar é fazer uma junção entre 'postagens' e 'comentários' que retornarão muita duplicação desnecessária de dados (com as mesmas informações de postagem repetidas em cada linha), o que significa que o tempo de processamento é gasto no banco de dados para reunir tudo e no meu ORM para analisar e desfazer tudo.
Mesmo que eu instrua meu ORM a carregar avidamente os comentários da postagem, o melhor que ele fará é enviar uma consulta para a postagem e, em seguida, uma segunda consulta para recuperar todos os comentários e reuni-los no lado do cliente, o que também é ineficiente.
Entendo que os bancos de dados relacionais são uma tecnologia comprovada (inferno, eles são mais antigos do que eu), e que houve uma tonelada de pesquisas neles ao longo das décadas e tenho certeza de que há uma boa razão para eles (e os Padrão SQL) foram projetados para funcionar da maneira que funcionam, mas não sei por que a abordagem descrita acima não é possível. Parece-me a maneira mais simples e óbvia de implementar um dos relacionamentos mais básicos entre registros. Por que os bancos de dados relacionais não oferecem algo assim?
(Isenção de responsabilidade: geralmente escrevo aplicativos da Web usando datastores Rails e NoSQL, mas recentemente venho testando o Postgres e realmente gosto muito. Não pretendo atacar bancos de dados relacionais, estou perplexo.)
Não estou perguntando como otimizar um aplicativo Rails ou como solucionar esse problema em um banco de dados específico. Estou perguntando por que o padrão SQL funciona dessa maneira quando parece contra-intuitivo e inútil para mim. Deve haver alguma razão histórica pela qual os designers originais do SQL queriam que seus resultados fossem assim.
Respostas:
CJ Date entra em detalhes sobre isso no capítulo 7 e no apêndice B do SQL e da teoria relacional . Você está certo, não há nada na teoria relacional que impeça o tipo de dados de um atributo de ser uma relação em si, desde que seja o mesmo tipo de relação em cada linha. Seu exemplo se qualificaria.
Mas Date diz que estruturas como essa são "geralmente - mas não invariavelmente - contra-indicadas" (ou seja, uma má idéia) porque hierarquias de relações são assimétricas . Por exemplo, uma transformação de estrutura aninhada em uma estrutura "plana" familiar nem sempre pode ser revertida para recriar o aninhamento.
Consultas, restrições e atualizações são mais complexas, mais difíceis de escrever e mais suportadas pelo RDBMS se você permitir atributos com valor de relação (RVAs).
Ele também confunde os princípios de design do banco de dados, porque a melhor hierarquia de relações não é tão clara. Devemos projetar uma relação de Fornecedores com um RVA aninhado para peças fornecidas por um determinado Fornecedor? Ou uma relação de peças com um RVA aninhado para fornecedores que fornecem uma determinada peça? Ou armazene os dois, para facilitar a execução de diferentes tipos de consultas?
Esse é o mesmo dilema que resulta do banco de dados hierárquico e dos modelos de banco de dados orientados a documentos . Eventualmente, a complexidade e o custo de acessar estruturas de dados aninhadas levam os designers a armazenar dados de forma redundante para facilitar a pesquisa por consultas diferentes. O modelo relacional desencoraja a redundância, para que os RVAs possam trabalhar contra os objetivos da modelagem relacional.
Pelo que entendi (não os usei), Rel e Dataphor são projetos RDBMS que suportam atributos com valor de relação.
Re comentário de @dportas:
Tipos estruturados fazem parte do SQL-99, e a Oracle os suporta. Mas eles não armazenam várias tuplas na tabela aninhada por linha da tabela base. O exemplo comum é um atributo "endereço" que parece ser uma única coluna da tabela base, mas possui sub-colunas adicionais para rua, cidade, código postal etc.
As tabelas aninhadas também são suportadas pelo Oracle e permitem várias tuplas por linha da tabela base. Mas não sei que isso faz parte do SQL padrão. E lembre-se da conclusão de um blog: "Eu nunca usarei uma tabela aninhada em uma instrução CREATE TABLE. Você gasta todo o seu tempo UN-NESTING-los para torná-los úteis novamente!"
fonte
x
pode ter o valor do número inteiro 42). As mesmas operações se aplicam a relações e relvars, portanto, sua estrutura precisa ser compatível.Alguns dos primeiros sistemas de banco de dados foram baseados no modelo Hierarchical Database . Isso representou dados em uma árvore como estrutura com pai e filhos, como você está sugerindo aqui. O HDMS foi amplamente substituído pelos bancos de dados criados com base no modelo relacional. As principais razões para isso foram que o RDBMS podia modelar relacionamentos "muitos para muitos" que eram difíceis para bancos de dados hierárquicos e que o RDBMS podia facilmente executar consultas que não faziam parte do design original, enquanto o HDBMS o restringia a consultar os caminhos especificados no tempo de design.
Ainda existem alguns exemplos de sistemas hierárquicos de banco de dados em estado selvagem, particularmente o registro do Windows e o LDAP.
Cobertura extensiva deste assunto está disponível no seguinte artigo
fonte
Suponho que sua pergunta esteja realmente centrada no fato de que, embora os bancos de dados sejam baseados em uma lógica sólida e configurem bases teroréticas, eles executam um trabalho muito bom ao armazenar, manipular e recuperar dados em conjuntos (bidimensionais), garantindo integridade referencial, simultaneidade e muitas outras coisas, eles não fornecem um recurso (adicional) de enviar (e receber) dados no que se poderia chamar de formato orientado a objeto ou formato hierárquico.
Em seguida, você afirma que "mesmo que eu instrua meu ORM a carregar avidamente os comentários da postagem, o melhor a fazer é enviar uma consulta para a postagem e, em seguida, uma segunda consulta para recuperar todos os comentários e reuni-los. do lado do cliente, o que também é ineficiente " .
Não vejo nada de ineficiente no envio de 2 consultas e no recebimento de 2 lotes de resultados com:
Eu diria que essa é (quase) a maneira mais eficiente (quase, porque você realmente não precisa das
posts.id
colunas e nem todascomments.*
)Como Todd apontou em seu comentário, você não deve pedir ao banco de dados para retornar dados prontos para exibição. É o trabalho do aplicativo para fazer isso. Você pode escrever (uma ou algumas) consultas para obter os resultados necessários para cada operação de exibição, para que não haja duplicação desnecessária nos dados enviados pelo cabo (ou pelo barramento de memória) do banco de dados para o aplicativo.
Na verdade, não posso falar sobre ORMs, mas talvez alguns deles possam fazer parte desse trabalho para nós.
Técnicas semelhantes podem ser usadas na entrega de dados entre um servidor web e um cliente. Outras técnicas (como cache) são usadas para que o banco de dados (ou a web ou outro servidor) não seja sobrecarregado com solicitações duplicadas.
Meu palpite é que os padrões, como o SQL, são melhores se permanecerem especializados em uma área e não tentarem cobrir todas as áreas de um campo.
Por outro lado, o comitê que define o padrão SQL pode pensar de outra maneira no futuro e fornecer padronização para esse recurso adicional. Mas não é algo que possa ser projetado em uma noite.
fonte
Não sou capaz de responder com uma resposta adequada e argumentada; portanto, sinta-se à vontade para me rebaixar ao esquecimento se estiver errado (mas, por favor, corrija-me para que possamos aprender algo novo). Penso que a razão é que os bancos de dados relacionais estão centrados no modelo relacional, que por sua vez se baseia em algo que não sei nada sobre chamado "lógica de primeira ordem". O que você pode perguntar provavelmente não se encaixa conceitualmente na estrutura matemática / lógica dos bancos de dados relacionais. Além disso, o que você pede geralmente é resolvido facilmente pelos bancos de dados de gráficos, dando mais dicas de que é a conceituação subjacente do banco de dados que entra em conflito com o que você deseja alcançar.
fonte
Eu sei que pelo menos o SQLServer oferece suporte a consultas aninhadas quando você usa FOR XML.
O problema aqui não é a falta de suporte do RDBMS, mas a falta de suporte de tabelas aninhadas nas tabelas.
Além disso, o que impede você de usar uma junção interna?
Você pode olhar realmente para a junção interna como uma tabela aninhada, apenas o conteúdo dos 2 primeiros campos é repetido uma vez. Eu não me preocuparia muito com o desempenho da junção, a única parte lenta de uma consulta como essa é a io do banco de dados para o cliente. Isso só será um problema quando o conteúdo contiver uma grande quantidade de dados. Nesse caso, eu sugeriria duas consultas, uma com
select id, content
e outra com uma junção interna eselect posts.id, comments.*
. Isso é dimensionado mesmo com várias postagens, pois você ainda usaria apenas 2 consultas.fonte
for xml
.Na verdade, o Oracle suporta o que você deseja, mas é necessário agrupar a subconsulta com a palavra-chave "cursor". Os resultados são buscados através do cursor aberto. Em Java, por exemplo, os comentários apareceriam como conjuntos de resultados. Mais sobre isso, consulte a documentação da Oracle sobre "Expressão CURSOR"
fonte
Alguns suportam aninhamento (hierárquico).
Se você quisesse uma consulta, poderia ter uma tabela que se auto-referencia. Alguns RDMS suportam esse conceito. Por exemplo, com o SQL Server, é possível usar CTEs (Common Table Expressions) para uma consulta hierárquica.
No seu caso, as postagens estariam no nível 0 e, em seguida, todos os comentários estariam no nível 1.
As outras opções são 2 consultas ou um ingresso com algumas informações extras para cada registro retornado (que outros mencionaram).
Exemplo de hierarquia:
https://stackoverflow.com/questions/14274942/sql-server-cte-and-recursion-example
No link acima, o EmpLevel mostra o nível do aninhamento (ou hierarquia).
fonte
Sinto muito, não tenho certeza se entendi exatamente o seu problema.
No MSSQL, você pode apenas executar 2 instruções SQL.
E ele retornará seus 2 conjuntos de resultados simultaneamente.
fonte
RDBMs são baseados na teoria e se apegam à teoria. Isso permite uma boa consistência e confiabilidade comprovada matematicamente.
Como o modelo é simples e, novamente, baseado na teoria, facilita para as pessoas a otimização e muitas implementações. Isso é diferente do NoSQL, onde todo mundo faz um pouco diferente.
No passado, houve tentativas de criar bancos de dados hierárquicos, mas o IIRC (não é possível pesquisar no Google) houve problemas (ciclos e igualdade vêm à mente).
fonte
Você tem uma necessidade específica. Seria preferível extrair dados de um banco de dados no formato desejado, para que você possa fazer o que quiser.
Alguns bancos de dados não funcionam tão bem, mas não é impossível construí-los para fazê-lo de qualquer maneira. Deixar a formatação para outros aplicativos é a recomendação atual, mas não justifica por que isso não pode ser feito.
O único argumento que tenho contra a sua sugestão é ser capaz de lidar com esse conjunto de resultados de maneira "sql". Seria uma má idéia criar um resultado no banco de dados e não poder trabalhar com ele ou manipulá-lo até certo ponto. Digamos que eu criei uma exibição criada da maneira que você sugere, como incluí-la em outra instrução select? Os bancos de dados gostam de obter resultados e fazer coisas com eles. Como eu o juntaria a outra mesa? Como eu compararia seu conjunto de resultados com outro?
O benefício dos RDMSs é a flexibilidade do sql. A sintaxe para selecionar dados de uma tabela está bem próxima de uma lista de usuários ou outros objetos no sistema (pelo menos esse é o objetivo). Não tenho certeza se há razão para fazer algo completamente diferente. Eles nem chegaram ao ponto de manipular código / cursores procedimentais ou BLOBS de dados com muita eficiência.
fonte
Na minha opinião, é principalmente por causa do SQL e da maneira como as consultas agregadas são executadas - funções e agrupamentos agregados são executados em grandes conjuntos de linhas bidimensionais para retornar resultados. É assim que é desde o início e é muito rápido (a maioria das soluções NoSQL são muito lentas com agregação e dependem de esquema desnormalizado em vez de consultas complexas)
Obviamente, o PostgreSQL possui alguns recursos do banco de dados orientado a objetos. De acordo com esses e-mails ( mensagem ), você pode obter o que precisa criando agregados personalizados.
Pessoalmente, estou usando estruturas como o Doctrine ORM (PHP), que agregam o lado do aplicativo e suportam recursos como carregamento lento para aumentar o desempenho.
fonte
O PostgreSQL suporta uma variedade de tipos de dados estruturados, incluindo Arrays e JSON . Usando SQL ou uma das linguagens processuais incorporadas, você pode criar valores com uma estrutura arbitrariamente complexa e devolvê-los ao seu aplicativo. Você também pode criar tabelas com colunas de qualquer um dos tipos estruturados, embora considere cuidadosamente se está desnormalizando desnecessariamente seu design.
fonte