Escalabilidade tem tudo a ver com pré-computação, espalhando ou reduzindo o trabalho repetido ao essencial, a fim de minimizar o uso de recursos por unidade de trabalho. Para escalar bem, você não faz nada que não precisa em volume e as coisas que você realmente faz são feitas com a maior eficiência possível.
Nesse contexto, é claro que juntar duas fontes de dados separadas é relativamente lento, pelo menos em comparação com não juntá-las, porque é um trabalho que você precisa fazer ao vivo no ponto em que o usuário o solicita.
Mas lembre-se de que a alternativa é não ter mais duas partes separadas de dados; você tem que colocar os dois pontos de dados diferentes no mesmo registro. Você não pode combinar duas partes diferentes de dados sem uma consequência em algum lugar, então certifique-se de entender a compensação.
A boa notícia é que os bancos de dados relacionais modernos são bons em associações. Você não deve realmente pensar em junções como lentas com um bom banco de dados bem usado. Existem várias maneiras amigáveis de escalabilidade para obter junções brutas e torná-las muito mais rápidas:
- Junte-se a uma chave substituta (coluna autonumer / identidade) em vez de uma chave natural. Isso significa comparações menores (e, portanto, mais rápidas) durante a operação de junção
- Índices
- Visualizações materializadas / indexadas (pense nisso como uma junção pré-calculada ou desnormalização gerenciada )
- Colunas calculadas. Você pode usar isso para hash ou de outra forma pré-calcular as colunas-chave de uma junção, de forma que o que seria uma comparação complicada para uma junção agora seja muito menor e potencialmente pré-indexado.
- Partições de tabela (ajuda com grandes conjuntos de dados, distribuindo a carga em vários discos ou limitando o que poderia ter sido uma análise de tabela para uma análise de partição)
- OLAP (pré-calcula os resultados de certos tipos de consultas / junções. Não é bem verdade, mas você pode pensar nisso como uma desnormalização genérica )
- Replicação, grupos de disponibilidade, envio de log ou outros mecanismos para permitir que vários servidores respondam a consultas de leitura para o mesmo banco de dados e, assim, dimensione sua carga de trabalho entre vários servidores.
- Uso de uma camada de cache como o Redis para evitar a repetição de consultas que precisam de junções complexas.
Eu iria mais longe e diria que a principal razão pela qual os bancos de dados relacionais existem é para permitir que você faça junções com eficiência * . Certamente não é apenas para armazenar dados estruturados (você pode fazer isso com construções de arquivo simples como csv ou xml). Algumas das opções que listei permitirão que você construa completamente sua junção com antecedência, de modo que os resultados já estejam prontos antes de você emitir a consulta - como se você tivesse desnormalizado os dados (reconhecidamente ao custo de operações de gravação mais lentas).
Se você tiver uma junção lenta, provavelmente não está usando o banco de dados corretamente.
A desnormalização deve ser feita somente depois que essas outras técnicas falharem. E a única maneira de realmente julgar o "fracasso" é definir metas de desempenho significativas e comparar essas metas. Se você não mediu, é muito cedo para pensar na desnormalização.
* Ou seja, existem como entidades distintas de meras coleções de tabelas. Um motivo adicional para um rdbms real é o acesso simultâneo seguro.
As junções podem ser mais lentas do que evitá-las por meio da desnormalização, mas se usadas corretamente (junção em colunas com índices apropriados e assim por diante) elas não são inerentemente lentas .
A desnormalização é uma das muitas técnicas de otimização que você pode considerar se o seu esquema de banco de dados bem projetado exibir problemas de desempenho.
fonte
o artigo diz que eles são lentos quando comparados à ausência de junções. isso pode ser alcançado com a desnormalização. portanto, há uma compensação entre velocidade e normalização. não se esqueça da otimização prematura também :)
fonte
Em primeiro lugar, a raison d'être (razão de ser) de um banco de dados relacional é ser capaz de modelar relacionamentos entre entidades. As junções são simplesmente os mecanismos pelos quais atravessamos esses relacionamentos. Eles certamente têm um custo nominal, mas sem junções, realmente não há razão para ter um banco de dados relacional.
No mundo acadêmico, aprendemos coisas como as várias formas normais (1ª, 2ª, 3ª, Boyce-Codd, etc.), e aprendemos sobre diferentes tipos de chaves (primária, estrangeira, alternativa, única, etc.) e como essas coisas se encaixam para criar um banco de dados. E aprendemos os rudimentos de SQL e também manipulamos a estrutura e os dados (DDL e DML).
No mundo corporativo, muitos dos conceitos acadêmicos se revelaram substancialmente menos viáveis do que fomos levados a acreditar. Um exemplo perfeito é a noção de chave primária. Academicamente, é esse atributo (ou coleção de atributos) que identifica exclusivamente uma linha na tabela. Portanto, em muitos domínios de problemas, a chave primária acadêmica adequada é um composto de 3 ou 4 atributos. No entanto, quase todo mundo no mundo corporativo moderno usa um inteiro sequencial gerado automaticamente como a chave primária de uma tabela. Por quê? Duas razões. A primeira é porque torna o modelo muito mais limpo quando você está migrando FKs para todos os lugares. A segunda, e mais pertinente a essa questão, é que recuperar dados por meio de junções é mais rápido e mais eficiente em um único inteiro do que em 4 colunas varchar (como já foi mencionado por algumas pessoas).
Vamos cavar um pouco mais fundo agora em dois subtipos específicos de bancos de dados do mundo real. O primeiro tipo é um banco de dados transacional. Essa é a base para muitos aplicativos de e-commerce ou gerenciamento de conteúdo que conduzem sites modernos. Com um banco de dados de transação, você está otimizando fortemente em direção ao "rendimento da transação". A maioria dos aplicativos comerciais ou de conteúdo precisa equilibrar o desempenho de consulta (de certas tabelas) com o desempenho de inserção (em outras tabelas), embora cada aplicativo tenha seus próprios problemas específicos de negócios para resolver.
O segundo tipo de banco de dados do mundo real é um banco de dados de relatórios. Eles são usados quase exclusivamente para agregar dados de negócios e gerar relatórios de negócios significativos. Eles são tipicamente moldados de forma diferente dos bancos de dados de transações onde os dados são gerados e são altamente otimizados para velocidade de carregamento de dados em massa (ETLs) e desempenho de consulta com conjuntos de dados grandes ou complexos.
Em cada caso, o desenvolvedor ou DBA precisa equilibrar cuidadosamente as curvas de funcionalidade e desempenho, e há muitos truques para melhorar o desempenho em ambos os lados da equação. No Oracle, você pode fazer o que é chamado de "plano de explicação" para ver especificamente como uma consulta é analisada e executada. Você está procurando maximizar o uso adequado de índices pelo banco de dados. Um não-não realmente desagradável é colocar uma função na cláusula where de uma consulta. Sempre que você fizer isso, você garante que o Oracle não usará nenhum índice nessa coluna específica e provavelmente verá uma varredura de tabela completa ou parcial no plano de explicação. Esse é apenas um exemplo específico de como uma consulta pode ser escrita que acaba sendo lenta e não tem nada a ver com junções.
E enquanto estamos falando sobre varreduras de tabela, elas obviamente afetam a velocidade da consulta proporcionalmente ao tamanho da tabela. Uma varredura completa da tabela de 100 linhas nem é perceptível. Execute a mesma consulta em uma tabela com 100 milhões de linhas e você precisará voltar na próxima semana para o retorno.
Vamos falar sobre normalização por um minuto. Este é outro tópico acadêmico amplamente positivo que pode ser excessivamente estressado. Na maioria das vezes, quando falamos sobre normalização, realmente queremos dizer a eliminação de dados duplicados, colocando-os em sua própria tabela e migrando um FK. As pessoas geralmente ignoram toda a coisa de dependência descrita por 2NF e 3NF. E ainda assim, em um caso extremo, certamente é possível ter um banco de dados BCNF perfeito que é enorme e uma besta completa para escrever código porque é muito normalizado.
Então, onde nos equilibramos? Não existe uma única resposta melhor. Todas as melhores respostas tendem a ser um meio-termo entre facilidade de manutenção da estrutura, facilidade de manutenção de dados e facilidade de criação / manutenção de código. Em geral, quanto menos duplicação de dados, melhor.
Então, por que as junções às vezes são lentas? Às vezes, é um design relacional ruim. Às vezes, é uma indexação ineficaz. Às vezes, é um problema de volume de dados. Às vezes, é uma consulta escrita de maneira horrível.
Desculpe por uma resposta tão prolixa, mas me senti compelido a fornecer um contexto mais substancial em torno de meus comentários, em vez de apenas recitar uma resposta de quatro pontos.
fonte
Pessoas com bancos de dados do tamanho de um terrabyte ainda usam junções, se eles podem fazê-los funcionar em termos de desempenho, então você também pode.
Existem muitos motivos para não desnaturar. Primeiro, a velocidade das consultas selecionadas não é a única ou mesmo a principal preocupação com os bancos de dados. A integridade dos dados é a primeira preocupação. Se você desnormalizar, terá que implementar técnicas para manter os dados desnormalizados à medida que os dados pai mudam. Portanto, suponha que você armazene o nome do cliente em todas as tabelas em vez de unir à tabela do cliente no client_Id. Agora, quando o nome do cliente muda (100% de chance de alguns dos nomes dos clientes mudarem com o tempo), agora você precisa atualizar todos os registros do filho para refletir essa mudança. Se você fizer isso com uma atualização em cascata e tiver um milhão de registros de filhos, quão rápido você acha que isso vai ser e quantos usuários vão sofrer problemas de bloqueio e atrasos em seus trabalhos enquanto isso acontece? Além disso, a maioria das pessoas que desnormalizam porque "
A desnormalização é um processo complexo que requer um entendimento completo do desempenho e integridade do banco de dados para ser feito corretamente. Não tente desnormalizar, a menos que você tenha esse conhecimento na equipe.
As junções são bastante rápidas se você fizer várias coisas. Primeiro use uma chave suggorgate, uma junção interna é quase sempre a junção mais rápida. Em segundo lugar, sempre indexe a chave estrangeira. Use tabelas derivadas ou condições de junção para criar um conjunto de dados menor para filtrar. Se você tiver um banco de dados grande e muito complexo, contrate um profissional de banco de dados com experiência em particionamento e gerenciamento de bancos de dados enormes. Existem várias técnicas para melhorar o desempenho sem eliminar as junções.
Se você só precisa de capacidade de consulta, então sim, você pode projetar um datawarehouse que pode ser desnormalizado e preenchido por meio de uma ferramenta ETL (otimizada para velocidade) e não pela entrada de dados do usuário.
fonte
As junções são lentas se
Portanto, é verdade, quanto maiores seus conjuntos de dados, mais processamento você precisará para uma consulta, mas verificar e trabalhar nas três primeiras opções acima geralmente produzirá ótimos resultados.
Sua fonte oferece a desnormalização como uma opção. Isso é bom apenas enquanto você esgotou as alternativas melhores.
fonte
As junções podem ser lentas se grandes porções de registros de cada lado precisarem ser verificadas.
Como isso:
Mesmo que um índice seja definido em
account_customer
, todos os registros desse último ainda precisam ser verificados.Para a lista de consulta this, os otimizadores decentes provavelmente nem mesmo considerarão o caminho de acesso do índice, fazendo a
HASH JOIN
ou a emMERGE JOIN
vez disso.Observe que para uma consulta como esta:
a junção provavelmente será rápida: primeiro, um índice on
customer_last_name
será usado para filtrar todos os Stellphlug's (que, obviamente, não são muito numerosos), então uma varredura de índiceaccount_customer
será emitida para cada Stellphlug para encontrar suas transações.Apesar do fato de que esses podem ter bilhões de registros em
accounts
ecustomers
, apenas alguns precisarão realmente ser digitalizados.fonte
accounts(account_customer)
maioria dos RDBMSes, ele usará esse índice para descobrir exatamente quais linhas docustomers
banco de dados precisam ser verificadas.HASH JOIN
seria muito mais rápido, então é o que será usado, exceto em todos os principais bancos de dadosMySQL
, exceto , que apenas fará o iníciocustomers
em um loop aninhado (já que é menor em tamanho)Joins are fast.
As junções devem ser consideradas uma prática padrão com um esquema de banco de dados normalizado corretamente. As junções permitem que você junte grupos distintos de dados de uma forma significativa. Não tema a adesão.A ressalva é que você deve compreender a normalização, a junção e o uso adequado dos índices.
Cuidado com a otimização prematura, pois a falha número um de todos os projetos de desenvolvimento é cumprir o prazo. Depois de concluir o projeto e entender as compensações, você pode quebrar as regras se puder justificar.
É verdade que o desempenho da junção é degradado de forma não linear à medida que o tamanho do conjunto de dados aumenta. Portanto, ele não é escalável tão bem quanto as consultas de uma única tabela, mas ainda o faz.
Também é verdade que um pássaro voa mais rápido sem asas, mas apenas para baixo.
fonte
As junções exigem processamento extra, pois precisam examinar mais arquivos e mais índices para "juntar" os dados. No entanto, "conjuntos de dados muito grandes" são todos relativos. Qual é a definição de grande? No caso de JOINs, acho que é uma referência a um grande conjunto de resultados, não a esse conjunto de dados geral.
A maioria dos bancos de dados pode processar rapidamente uma consulta que seleciona 5 registros de uma tabela primária e junta 5 registros de uma tabela relacionada para cada registro (assumindo que os índices corretos estejam no lugar). Essas tabelas podem ter centenas de milhões de registros cada, ou até bilhões.
Uma vez que seu conjunto de resultados comece a crescer, as coisas vão desacelerar. Usando o mesmo exemplo, se a tabela primária resultar em 100 mil registros, haverá 500 mil registros "unidos" que precisam ser encontrados. Retirar tantos dados do banco de dados com atrasos na adição.
Não evite JOINs, apenas saiba que pode ser necessário otimizar / desnormalizar quando os conjuntos de dados ficarem "muito grandes".
fonte
Também do artigo que você citou:
e
e
O artigo discute mega-sites como o Ebay. Nesse nível de uso, você provavelmente terá que considerar algo diferente do gerenciamento de banco de dados relacional simples. Mas no curso "normal" dos negócios (aplicativos com milhares de usuários e milhões de registros), as abordagens mais caras e sujeitas a erros são exageradas.
fonte
As junções são consideradas uma força oposta à escalabilidade porque normalmente são o gargalo e não podem ser facilmente distribuídas ou paralelas.
fonte
Tabelas projetadas corretamente contendo os indicadores adequados e consultas escritas corretamente nem sempre são lentas. Onde você já ouviu isso:
não tem ideia do que estão falando !!! A maioria das junções será muito rápida. Se você tiver que unir muitas linhas de uma vez, poderá sofrer um golpe em comparação com uma tabela desnormalizada, mas isso remete a Tabelas projetadas corretamente, saiba quando desnormalizar e quando não. em um sistema de relatórios pesado, divida os dados em tabelas desnormalizadas para relatórios ou até mesmo crie um data warehouse. Em um sistema transacional pesado normalize as tabelas.
fonte
A quantidade de dados temporários gerados pode ser enorme com base nas junções.
Por exemplo, um banco de dados aqui no trabalho tinha uma função de pesquisa genérica em que todos os campos eram opcionais. A rotina de pesquisa fez uma junção em todas as tabelas antes de a pesquisa começar. Isso funcionou bem no início. Mas, agora que a tabela principal tem mais de 10 milhões de linhas ... nem tanto. As pesquisas agora levam 30 minutos ou mais.
Fui incumbido de otimizar o procedimento armazenado de pesquisa.
A primeira coisa que fiz foi se algum dos campos da tabela principal estivesse sendo pesquisado, fiz uma seleção para uma tabela temporária apenas nesses campos. ENTÃO, juntei todas as tabelas com aquela tabela temporária antes de fazer o resto da pesquisa. Pesquisas em que um dos campos principais da tabela agora levam menos de 10 segundos.
Se nenhum dos campos da tabela principal começar a ser pesquisado, faço otimizações semelhantes para outras tabelas. Quando terminei, nenhuma pesquisa leva mais de 30 segundos, com a maioria menos de 10.
A utilização da CPU do servidor SQL também diminuiu.
fonte
Embora as junções (presumivelmente devido a um design normalizado) possam obviamente ser mais lentas para recuperação de dados do que uma leitura de uma única tabela, um banco de dados desnormalizado pode ser lento para operações de criação / atualização de dados, uma vez que a pegada da transação geral não será mínima.
Em um banco de dados normalizado, uma parte dos dados viverá em apenas um lugar, portanto, a área ocupada por uma atualização será a mínima possível. Em um banco de dados desnormalizado, é possível que a mesma coluna em várias linhas ou entre tabelas precise ser atualizada, o que significa que a área de cobertura seria maior e a chance de bloqueios e impasses pode aumentar.
fonte
Bem, sim, selecionar linhas de uma tabela desnormalizada (assumindo índices decentes para sua consulta) pode ser mais rápido do que selecionar linhas construídas a partir da junção de várias tabelas, principalmente se as junções não tiverem índices eficientes disponíveis.
Os exemplos citados no artigo - Flickr e eBay - são casos excepcionais da IMO, portanto têm (e merecem) respostas excepcionais. O autor chama a atenção para a falta de RI e a extensão da duplicação de dados no artigo.
A maioria dos aplicativos - novamente, IMO - se beneficia da validação e duplicação reduzida fornecida pelos RDBMSs.
fonte
Eles podem ser lentos se feitos de maneira descuidada. Por exemplo, se você fizer um 'select *' em uma junção, provavelmente demorará um pouco para obter as coisas de volta. No entanto, se você escolher cuidadosamente quais colunas retornar de cada tabela e com os índices apropriados no lugar, não haverá problema.
fonte