Restrições de integridade em um banco de dados relacional - devemos ignorá-las?


10

Estou em uma discussão permanente com os desenvolvedores da empresa em que trabalho, porque eles dizem que é melhor se livrar da imposição de relacionamentos (por meio das definições de restrição FOREIGN KEY) em um banco de dados relacional, a fim de acelerar grandes consultas e obter melhores resultados. desempenho.

A plataforma em consideração é o MySQL 5.x, e nenhuma FOREIGN KEY foi configurada; até algumas restrições de PRIMARY KEY das tabelas relevantes estão ausentes, o que, pelo menos para mim, não é razoável. Talvez eles estejam certos e eu esteja errado, mas não tenho argumentos suficientes para discutir sobre essa situação.

Essa tem sido a abordagem preferida há três anos. Sou novo nesta empresa (apenas um mês), mas, como o produto “funciona”, há uma hesitação em aprimorar o banco de dados; No entanto, a primeira coisa que notei é uma página que leva 1 minuto para carregar (sim, 60 segundos!).

Uma das reivindicações por trás do estado atual é que um banco de dados "desnormalizado" é mais rápido que um banco de dados normalizado, mas não acredito que isso seja verdade.

A maioria das consultas relevantes inclui operações JOIN, o que as torna executadas muito, muito, muito lentamente, com grandes quantidades de dados (o banco de dados contém milhões de linhas).

Geralmente, o manuseio das operações “CRUD” é implementado no nível do código do programa aplicativo; por exemplo, para excluir alguns dados de, digamos TableA:

  • é necessário primeiro verificar em tempo real se existe alguma relação entre as linhas de TableAe TableB,
  • caso o referido relacionamento seja "detectado", o código do programa do aplicativo não permitirá EXCLUIR as linhas pertinentes, mas
  • se, por algum motivo, o código do programa do aplicativo falhar, a operação DELETE será "bem-sucedida", independentemente de haver algum relacionamento relacionado às linhas e tabelas envolvidas.

Questão

Você poderia me ajudar a elaborar uma resposta boa, precisa e sólida para enriquecer o debate?


Nota : Talvez algo como isso já tenha sido solicitado (e respondido) antes, mas não consegui encontrar nada por meio do Google.


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Paul White 9

Respostas:


12

Se, como declarado em sua postagem, a intenção é criar um banco de dados relacional (RDB por brevidade) e, portanto, espera-se que funcione como tal, a resposta curta será:

  • Não, você não deve ignorar as restrições de integridade de dados .

O objetivo principal deve ser o de gerenciar os dados pertinentes, um ativo organizacional bastante valioso e uma maneira confiável de alcançar esse objetivo é empregar meios técnicos que são suportados por uma teoria sólida.

Assim, como profissionais de banco de dados, você pode tirar proveito dos mecanismos de modelo relacional modernos e modernos fornecidos pelo Dr. EF Codd para impor regras de negócios e evitar os problemas que eventualmente surgiriam se eles não forem utilizados.

A esse respeito, compartilharei (a) minha visão geral das restrições e (b) várias considerações sobre o estado das coisas no banco de dados e o ambiente de trabalho em questão da seguinte forma.

Restrições de chave estrangeira, relacionamentos de dados e integridade referencial

Um RDB deve refletir as características do contexto de negócios de interesse com alta precisão, o que definitivamente requer uma análise aprofundada em nível conceitual liderada por um modelador ou designer que segue as melhores práticas, contando com a assistência indispensável dos especialistas em negócios. Essa análise deve fornecer a identificação e formulação corretas das regras de negócios aplicáveis .

Consequentemente, se esse modelador identificou a existência de inter-relações entre os dados relevantes, ele ou ela deve configurar as restrições de nível lógico correspondentes para que o sistema de gerenciamento de banco de dados (DBMS) possa garantir que os dados permaneçam consistentes com as características exatas e regras determinadas na análise acima mencionada em todos os momentos .

Com relação ao banco de dados em discussão, pode-se inferir que as inter-relações pertinentes foram identificadas, pois você menciona que existe uma tentativa processual (e fácil de contornar) de aplicá-las fora das instalações do DBMS, por meio do código do programa aplicativo (que é uma abordagem pré-relacional) que, em qualquer caso, precisa "tocar" o banco de dados para tentar validar a totalidade das referidas inter-relações.

No entanto, como você sabe, essa não é a técnica ideal para proteger a integridade referencial , porque a ciência relacional prescreveu um instrumento muito poderoso para esse fim, ou seja, restrições de FOREIGN KEY (FK). Essas restrições são muito fáceis de criar (por meio da abordagem declarativa superior), pois são frases únicas que evitam recorrer a procedimentos ad hoc desnecessários e propensos a erros. É muito útil observar que a velocidade de execução das restrições do FK foi altamente otimizada por programadores especializados (e os principais fornecedores de plataformas já trabalham nisso há décadas).

Além disso, como um RDB deve ser um componente de software independente (autoprotetor, autoexplicativo etc.) capaz de ser acessado por vários programas aplicativos (desktop, automático, web, móvel, combinações dos mesmos), não deve ser "Acoplado" ao código de qualquer um desses aplicativos.

Da mesma forma, os dados - sendo um recurso organizacional significativo - naturalmente tendem a sobreviver a programas de aplicativos, programadores de aplicativos, plataformas de desenvolvimento de aplicativos e paradigmas de programação.

Restrições de PRIMARY KEY e implicações de linhas duplicadas

Quando, conceitualmente, um tipo específico de coisa é considerado significativo em um ambiente de negócios, um modelador de banco de dados precisa (1) determinar suas características relevantes - ou seja, suas propriedades -, confirmar esse tipo de coisa como um protótipo de instância de entidade - ou seja, um tipo de entidade - e (2) representa-o por meio de uma tabela que é integrada por uma ou mais colunas em um design lógico.

Então, assim como é fundamental distinguir cada instância individual de um determinado tipo de entidade no mundo real, cada linha incluída em uma tabela também deve ser diferenciada exclusivamente. Se uma tabela não tiver nenhuma KEY declarada, ela reterá duplicatas e, se houver duas ou mais linhas que mantêm exatamente os mesmos valores, todas elas terão o mesmo significado , todas elas representarão o mesmo fato .

Nesse ponto, linhas duplicadas devem ser descartadas devido a vários motivos. Do ponto de vista teórico, o designer deve garantir que cada linha seja sempre única com o objetivo de ter tabelas que funcionem tão relacionalmente quanto a sub-linguagem de dados SQL permitir (com importantes repercussões nas operações de manipulação de dados). Além disso, do ponto de vista informacional, se várias linhas representam o mesmo fato, seu registro não é apenas supérfluo, mas prejudicial , como exemplificado abaixo:

  • Suponha que alguém tenha inserido duas linhas idênticas em uma determinada tabela.
  • Mais tarde, alguém chega e atualiza apenas uma ocorrência das duplicatas. Como conseqüência, a outra ocorrência não está mais atualizada.
  • Sucessivamente, outra pessoa atualiza a ocorrência que não havia sido modificada até o momento. Dessa maneira, ambas as duplicatas sofreram alterações diferentes em momentos distintos.
  • Depois disso, quando alguém estiver interessado em selecionar as informações transmitidas pelas linhas em questão, poderá encontrar duas "versões" diferentes.

Nesse caminho:

  • Qual "versão" pode ser considerada a correta e confiável?
  • Qual deles reflete o mundo real com precisão?

Como você sabe, esse fenômeno pode até ter implicações legais, uma circunstância que certamente é de enorme importância.

Além disso, o tempo e o esforço que devem ser empregados para lidar com tais contradições (talvez através de algum tipo de "sincronização de atualização") devem ser mais dedicados a tarefas que realmente produzem valor para sua organização. Portanto, reter linhas contraditórias deve ser evitado pelo design para manter intacta a consistência de um banco de dados.

É por isso que a identificação de uma PRIMARY KEY (PK) e a declaração da respectiva restrição devem sempre ser executadas pelo designer do banco de dados. Mas também deve ser mencionado que uma tabela pode ter mais de uma coluna ou combinação de colunas que contêm valores que identificam exclusivamente cada linha; como conseqüência, além de configurar uma restrição PK (idealmente estabelecida como PRIMÁRIA por motivos pragmáticos), o designer também deve declarar uma ou mais CHAVES ALTERNATIVAS (geralmente definidas por meio de uma ou mais restrições UNIQUE e NÃO NULA) quando aplicável (o que é bastante comum).

Outra propriedade vantajosa das PKs é que, quando “migradas” para outras tabelas para participar de FKs únicas ou compostas, elas podem ajudar a impor as proporções de cardinalidade dos relacionamentos existentes entre os dados. Tudo isso, sim, por meio de configurações declarativas simples e eficientes, garantidas pelo DBMS.

Restrições CHECK (atuais) e validação de linha única

Não esqueçamos a relevância das restrições CHECK (atuais) que, restringindo declarativamente o conjunto válido de valores de colunas de uma linha (que podem parecer simples, mas são de fato um recurso fundamental de um DBMS relacional), ajudam também a tornar certo de que as regras do contexto comercial são refletidas com precisão o tempo todo.

Como você marcou sua pergunta com a tag MySQL, deve-se mencionar que, infelizmente, essa plataforma permite a declaração desse tipo de restrição, mas, ao mesmo tempo, ignora sua aplicação! , situação que, compreensivelmente, foi relatada como um bug desde 2004 .

Nesse sentido, você teria que cuidar desse fator por outros meios, por exemplo, TRANSACÇÕES ÁCIDAS, DISPARADORES ou outros métodos dentro do próprio DBMS (consulte esta resposta do @ ypercubeᵀᴹ para obter informações sobre este assunto) para que os dados continuem a ser consistente.

Restrições de ASSERÇÃO: configurando regras de negócios adicionais de várias linhas e várias tabelas declarativamente

Um aspecto que, por qualquer motivo, é pouco suportado - se é que - pelos diferentes DBMSs do SQL, incluindo o MySQL, está permitindo restrições de várias linhas e várias tabelas de maneira declarativa - além de PKs e FKs, evidentemente -.

Por seu turno, o padrão SQL inclui ASSERÇÕES de muitos anos. Não sei quais regras do seu ambiente de negócios se beneficiariam dessa abordagem de validação em nível lógico, mas, como designer de banco de dados, considero que seria bastante útil restringir dados com uma ou mais ASSERÇÕES, embora eu deva mencionar isso no do ponto de vista dos desenvolvedores do DBMS, esse tipo de ferramenta primordial tem sido difícil de implementar no nível físico da abstração.

Parece que o fornecedor e / ou desenvolvedores da Oracle estão avaliando o suporte do ASSERTION desde 2016, e isso tornaria o DBMS mais compatível com o relacionamento e, portanto, mais robusto e competitivo. Eu acho que, se (i) seus consumidores continuarem pressionando e (ii) a Oracle for bem-sucedida na implementação, (iii) outros fornecedores / comunidades de DBMS precisarão habilitá-los também, e seu uso começará a se espalhar. Certamente, isso seria um enorme progresso no campo de gerenciamento de banco de dados e, sendo uma das ferramentas mais distintas previstas pelo Dr. Codd, eu pessoalmente espero que isso aconteça em breve.

Consistência dos dados e processo de tomada de decisão

Como discutido acima, um dos aspectos mais importantes de um RDB é que ele garante por si só a consistência dos dados que retém, e essa consistência só é atendida quando o RDB está em conformidade com as restrições de integridade declaradas pelo modelador.

Nesse sentido, é obrigatório ter tabelas de base (aquelas estabelecidas em uma estrutura DDL) cuja integridade esteja protegida para poder criar tabelas derivadas (por exemplo, uma instrução SELECT ou exibição que recupera colunas de várias tabelas) que sejam confiáveis , porque as tabelas derivadas precisam ser produzidas necessariamente em termos de tabelas base.

É sabido que as pessoas usam as informações como a principal ferramenta no processo de tomada de decisão organizacional (e no comum). Então, se as informações apresentadas por um banco de dados não forem coerentes e precisas, as decisões baseadas nessas informações não serão sólidas (para dizer o mínimo). É por isso que um RDB deve ser cuidadosamente projetado e implementado: ele deve ser construído para se tornar um recurso confiável que pode ajudar seus usuários a tomar decisões fundamentadas.

"Desnormalização"

Infelizmente, “um banco de dados 'desnormalizado' é mais rápido que um banco de dados normalizado” é um equívoco amplamente difundido, embora também seja um argumento que pode ser refutado em bases lógicas, físicas e pragmáticas.

Em primeiro lugar, a desnormalização implica necessariamente que uma tabela de base tenha sido previamente normalizada (em virtude de um procedimento formal , baseado na ciência, realizado no nível lógico de abstração de um banco de dados).

Portanto, supondo que a tabela tenha sido de fato normalizada corretamente, "desnormalizando-a" (que, em contraste com o significado formal da palavra, envolve anexar a ela colunas que pertencem a outras tabelas de um anúncio e também fazem parte dela moda hoc ) pode ajudar, por exemplo, a acelerar (no nível físico) o processamento de apenas uma ou algumas instruções SELECT específicas, enquanto esse curso de ação pode, ao mesmo tempo, minar a execução de muitos outros dados associados operações de manipulação (por exemplo, várias instruções INSERT, UPDATE, DELETE e SELECT ou combinações delas incluídas em uma única ou múltiplas TRANSACÇÕES ÁCIDAS).

Além disso, a desnormalização (formal ou informal) introduziria anomalias de atualização / modificação que deterioram a coerência do banco de dados, um problema que “pode” ser tratado por procedimentos complexos, dispendiosos e propensos a erros, quando tudo isso pode ser impedido de o começo.

Andaimes de nível físico que suportam tabelas normalizadas e "desnormalizadas"

Um layout lógico (abstrato) (design SQL-DDL) que deve ser utilizado no mundo real contém claramente repercussões físicas (concretas) que devem ser consideradas.

Dessa maneira, uma tabela "desnormalizada" seria necessariamente "mais larga" (mantendo colunas adicionais), o que significa que suas linhas seriam necessariamente mais pesadas (exigindo mais e maiores componentes no nível físico), de modo que os processos de computação subjacentes (por exemplo, , aqueles que têm a ver com o disco rígido ou a memória) podem facilmente ficar mais lentos.

Por outro lado, uma tabela normalizada que é obviamente "mais estreita" (com menos colunas) seria um elemento "mais leve" (servido por componentes físicos cada vez menores) que "se comporta mais rápido", o que aceleraria a série de ações relacionadas a por exemplo, gravação e leitura de dados.

Sendo assim, é muito conveniente (a) normalizar as tabelas relevantes formal e prudentemente, mantendo-as como tal, e (b) utilizar qualquer recurso de nível físico que possa otimizar a velocidade de recuperação e modificação de dados, por exemplo, implementar uma estratégia de indexação cuidadosa e eficiente, permitindo configurações adequadas de servidores de software e hardware, atualizando os recursos de largura de banda da rede etc.

O funcionamento do banco de dados em consideração

Os parágrafos a seguir da sua pergunta têm a ver com a velocidade das operações de recuperação de dados:

[A] s o produto “funciona”, há hesitação em aprimorar o banco de dados; no entanto, a primeira coisa que notei é uma página que leva 1 minuto para carregar (sim, 60 segundos!).

Se o carregamento de uma determinada página leva muito, é evidente que os usuários do sistema não estão recebendo um bom serviço; portanto, mesmo quando "funciona", seu funcionamento não parece ótimo, ponto que demonstra que suas intenções de tornar todo o ambiente (banco de dados e aplicativos) mais eficientes são bem sustentadas e mostram uma atitude muito construtiva.

Então, mesmo quando a ciência definitivamente o apoia e, portanto, você deve manter uma postura firme, sugiro abordar a situação de maneira diplomática, pois no final do dia, seus empregadores, colegas e você estão se unindo aos esforços para tornar toda a organização mais bem sucedido. Portanto, esse é um argumento que você deve enfatizar: enquanto eles estão fazendo outras coisas mais do que bem, melhorar as práticas gerais e específicas de gerenciamento de dados pode ajudar consideravelmente na produção de mais crescimento organizacional e individual.

A maioria das consultas relevantes inclui operações JOIN, o que as torna executadas muito, muito, muito lentamente, com grandes quantidades de dados (o banco de dados contém milhões de linhas).

Vale ressaltar que o operador JOIN é um elemento essencial e poderoso que pertence à manipulação relacional de dados. Então, embora plataformas mais robustas o atendam com execuções comparativamente mais rápidas, a circunstância que você descreve é ​​provavelmente um sintoma de um design não eficiente (nos níveis conceitual, lógico e físico de abstração). Então, minhas primeiras estimativas à vista são:

  • As configurações de INDEX podem exigir melhorias.
  • As definições de tipo e tamanho de colunas PK e FK precisam ser revisadas (e eu concordo totalmente com @ James James sobre suas considerações sobre PK , pois as KEYs compostas tendem a ser muito mais eficientes do que as substitutas anexadas nos casos apropriados).
  • Uma normalização adicional (formal, baseada na ciência) pode ajudar a aliviar esses problemas, devido ao fato de que, nas circunstâncias corretas (isto é, realizadas em um RDB bem projetado), os JOINs são executados muito rapidamente .

Além disso, sim, como o @TommCatt menciona em sua resposta , às vezes uma reescrita (lógica) de uma consulta modifica seu plano de execução (físico), acelerando a leitura / gravação de dados, que é um fator que deve ser decididamente levado em consideração.


11
Ótima resposta. Sempre me lembro ao considerar o desempenho de uma implementação que uma equipe de desenvolvedores muito mais inteligente do que eu tenho trabalhado nesses problemas há muito tempo. Os bancos de dados relacionais estão no coração dos sistemas mais enormes do mundo (Facebook e Twitter, para citar alguns óbvios).
Nick Bedford

9

A premissa básica de seus desenvolvedores está absolutamente errada. Chaves estrangeiras impactarão levemente o desempenho do DML do seu sistema. Eles não são usados ​​em consultas, portanto, não afetam seu desempenho. Portanto, seus desenvolvedores não sabem do que estão falando e são as últimas pessoas de quem você deve considerar o aconselhamento.

Chaves estrangeiras desempenham um papel crítico na manutenção da integridade de seus dados. Isso é muito mais importante do que qualquer pequena melhoria de desempenho obtida com a remoção deles (mesmo que fosse verdade).

Em nenhuma circunstância, remova os FKs de um banco de dados OLTP.

Além disso, a desnormalização às vezes acelera algumas consultas. Como eles dizem, depende. Ainda assim, mesmo se houver alguma melhoria na velocidade, geralmente não vale a pena o esforço extra para manter a integridade dos dados.

É muito raro quando o ajuste simples não oferece muito mais aprimoramento de velocidade do que a desnormalização. É aqui que um bom DBA pode (finalmente) ganhar seu salário. Você também pode ajustar suas consultas. Certa vez, fiz uma consulta que retornou uma resposta em não menos de 30 minutos e funcionou em menos de 8 segundos. Nenhuma alteração no banco de dados, apenas reescreva a consulta. É verdade que este é o meu melhor recorde pessoal, portanto sua milhagem pode variar, mas a desnormalização deve ser a última coisa que você tenta.

Você também pode impedir que as consultas mais complicadas sejam gravadas pelos desenvolvedores. Pergunte a eles quais dados eles desejam e em que formato eles desejam. Em seguida, forneça visualizações para fornecê-los. As consultas complicadas serão as visualizações. Os desenvolvedores precisam apenas escrever:

select <something> from <SomeView> where <whatever>;

Também estou assumindo que seu banco de dados é bem projetado. Um design ruim do banco de dados, ou mesmo pequenas partes dele, pode realmente atrasar as coisas. Trabalhei muitas vezes com tabelas muito grandes (bilhões de registros cada) com consultas que as uniram à esquerda e à direita e esperavam (e obtiveram) respostas em frações de segundo. O tamanho de uma tabela não é determinante da velocidade da consulta.

Eu realmente me arrepio quando alguém diz: "porque o produto 'funciona', há uma hesitação em aprimorar o banco de dados". Se essa "hesitação" é mais como "não está no meu relógio, amigo!" então você pode até começar a atualizar seu currículo. Nada de bom vem desse ambiente e você será responsabilizado por todas as falhas futuras, mesmo que você tenha pressionado por horas a fazer uma mudança que teria evitado a falha. Você ouvirá: "Agora não é um bom momento para fazer alterações" repetidamente. Direita. Boa sorte.


Uma coisa a observar é que, às vezes, você precisa de consultas diferentes para os mesmos dados, com base na quantidade de dados a serem retornados. Por exemplo, uma consulta que está retornando uma única linha (ou mesmo apenas uma contagem) pode ser melhor escrita de maneira diferente do que uma que retorna milhares de registros.
18720 Joe Z. #

2

Alterar o título altera a pergunta. FOREIGN KEYssão opcionais. Eles fazem:

  • Um FK cria implicitamente um INDEXem uma das tabelas. Esse índice pode ser adicionado manualmente. (Portanto, o FK não é necessário para isso.)
  • Um FK verifica a integridade. Esta é a principal reivindicação do FK à fama. Não é necessário um FK, pois seu aplicativo pode fazer verificações semelhantes ou decidir que não é necessário. Então...
  • A verificação de integridade custa algo em desempenho; por isso diminui a velocidade do processamento. (Isso geralmente não é grande coisa.)
  • FKs não fazem tudo o que todo mundo quer; este fórum está repleto de perguntas "por que os FKs não podem fazer X". Em particular, a CHECKopção não é posta em prática.
  • FKs podem CASCADEcoisas. (Pessoalmente, prefiro manter o controle e não assumir que o FK 'fará a coisa certa'.)

Bottom line for FKs: Algumas pessoas insistem em FKs; alguns produtos vivem perfeitamente bem sem eles. Você decide.

Livrar-se do PRIMARY KEYInnoDB é um grande erro. Por outro lado, livrar-se de um substituto AUTO_INCREMENTe usar uma PK "natural" composta de uma (ou mais) colunas é geralmente a coisa certa a se fazer. Um caso simples e comum é um número de muitos: muitos, como discutido aqui .

Com base na experiência pessoal, sugiro que 2/3 das tabelas sejam melhores em usar 'natural' em vez de auto_inc PK.


11
Então ... você confia em um aplicativo quase perfeito, porque se um desenvolvedor cometer um erro com um, DELETEpor exemplo, e você não tiver uma restrição no lado do banco de dados, acabará perdendo dados. Esta abordagem é válida, mas requer código intenso e bom teste, que eles não tinham :)
ReynierPM

A exclusão em excesso pode acontecer no aplicativo ou com o FK. Excluir muito pouco geralmente se torna óbvio. OTOH, já vi casos em que excluir muito pouco vale o custo - pense em uma "normalização" em que as coisas raramente são excluídas. As linhas extras, não utilizadas, são praticamente inofensivas.
Rick James

Vi um caso 'bom' para nenhum índice em uma tabela - uma tabela intermediária para ingestão em alta velocidade. É muito transitório (portanto, o InnoDB não é necessário) e só precisa ser lido completamente (portanto, nenhum índice é necessário).
Rick James

11
Observe um tema comum em minhas divagações: Não há uma resposta única; nenhum tamanho único.
Rick James

Se suas tabelas tiverem mil linhas; desempenho não é um problema. Se suas tabelas tiverem um bilhão de linhas, todas as "regras" sobre normalização, PKs, índices, FKs, UUIDs, etc, precisam ser examinadas. Caso contrário, o banco de dados derreterá.
Rick James
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.