“Nunca faça no código o que você pode fazer com que o SQL Server faça bem para você” - Isso é uma receita para um design ruim?

193

É uma ideia que ouvi repetida em alguns lugares. Alguns mais ou menos reconhecendo que uma vez que tentar resolver um problema puramente em SQL excede um certo nível de complexidade, você deve, de fato, estar manipulando-o em código.

A lógica por trás da ideia é que, para a grande maioria dos casos, o mecanismo de banco de dados fará um trabalho melhor em encontrar a maneira mais eficiente de concluir sua tarefa do que no código. Especialmente quando se trata de coisas como tornar os resultados condicionais em operações realizadas nos dados. Indiscutivelmente com motores modernos efetivamente JIT'ing + cache a versão compilada de sua consulta faria sentido na superfície.

A questão é se alavancar ou não o seu mecanismo de banco de dados dessa maneira é inerentemente uma má prática de design (e por quê). As linhas ficam mais embaçadas quando toda a lógica existe dentro do banco de dados e você está apenas atingindo-o através de um ORM.

    
por PhonicUK 22.03.2014 / 15:16
fonte

14 respostas

312

Nas palavras do leigo:

Essas são as coisas que o SQL faz para e, acredite ou não, eu já vi no código:

  • junta-se - codificar requereria manipulação complexa de matriz
  • filtragem de dados (onde) - de forma codificada, exigiria a inserção e exclusão de itens em listas
  • selecionando colunas - de forma codificada, seria necessária uma lista pesada ou manipulação de matriz
  • funções agregadas - de forma codificada, exigiria que as matrizes guardassem valores e casos complexos de comutação
  • integridade da chave estrangeira - de forma codificada, exigiria consultas antes da inserção e pressupõe que ninguém usará os dados fora do aplicativo
  • integridade da chave primária - de forma codificada, exigiria consultas antes da inserção e pressupõe que ninguém usará os dados fora do aplicativo

Fazer essas coisas em vez de depender de SQL ou do RDBMS leva a escrever toneladas de código sem valor agregado , o que significa mais código para depurar e manter. E isso, perigosamente, pressupõe que o banco de dados só será acessado através do aplicativo.

    
por 22.07.2013 / 18:40
fonte
120

Eu reformularia isso para "Nunca faça no código o que o SQL Server pode fazer por você bem ".

Coisas como manipulação de strings, regex funcionam e tal que eu não faria no SQL Server (com exceção do SQL CLR).

O acima tende a falar sobre coisas como - junções, definir operações e consultas. A intenção por trás disso é delegar grande parte do trabalho pesado para o SQL Server (no que é bom) e reduzir a quantidade de E / S possível (então deixe SQL fazer as junções e filtrar com uma cláusula WHERE , retornando um conjunto de dados muito menor do que o contrário).

    
por 23.10.2012 / 17:35
fonte
46

Never do in code what you can get the SQL server to do well for you (emphasis is mine)

A chave para a resposta é que você precisa procurar SQL fazendo algo bem, ao invés de simplesmente fazer algo, para você. SQL é uma linguagem incrivelmente poderosa. Juntamente com funções integradas, pode potencialmente fazer muitas coisas. No entanto, o fato de você poder fazer algo em SQL não deve ser uma desculpa para realmente fazer isso em SQL.

Meu critério específico para tomar uma decisão é analisar a quantidade de dados que você recebe e o número de viagens de ida e volta: se você pode reduzir a quantidade de dados enviando uma tarefa ao servidor, sem aumentar o número de ida e volta, a tarefa pertence ao servidor; se a quantidade de dados permanecer a mesma ou aumentar sem uma queda simultânea no número de viagens de ida e volta, a tarefa pertence ao seu código.

Considere estes exemplos:

  • Você armazena uma data de nascimento e precisa calcular a idade de um grupo de usuários. Você pode ter o SQL Server fazendo a subtração, ou você pode fazer isso no seu código. O número de viagens de ida e volta permanece o mesmo e a quantidade de dados enviados de volta para você aumenta. Portanto, uma solução baseada em código ganha
  • Você armazena uma data de nascimento e precisa encontrar usuários com idades entre 20 e 30. Você pode carregar todos os usuários de volta no cliente, fazer a subtração para encontrar a idade e, em seguida, fazer a filtragem, mas enviar a lógica para o SQL Server reduziria a quantidade de dados sem exigir viagens de ida e volta adicionais; portanto, a solução baseada em SQL ganha.
por 23.10.2012 / 18:03
fonte
20

Resumindo , seria correto dizer: "Nunca realize operações específicas do banco de dados em sua base de código", pois elas são melhores abordada em seu banco de dados.

Veja o exemplo das operações básicas definidas . Como você deve saber, o RDBMS foi criado para lidar com operações comuns de armazenamento e manipulação de dados.

Além disso, a escolha do projeto do banco de dados desempenha um papel importante . Ter um RDBMS (MS SQL, Oracle, etc.) é diferente dos bancos de dados NoSQL, como o RavenDB.

    
por 24.10.2012 / 18:15
fonte
13

Como regra, seu banco de dados tem mais informações para trabalhar do que seu aplicativo e pode realizar operações de dados comuns com mais eficiência. Seu banco de dados mantém índices, por exemplo, enquanto seu aplicativo teria que indexar os resultados da pesquisa na hora. Assim, como todo o resto é igual, sua carga de trabalho geral pode ser diminuída empurrando o trabalho para o banco de dados em vez do aplicativo.

Mas à medida que seu produto é dimensionado, normalmente fica mais fácil dimensionar seu aplicativo do que dimensionar seu banco de dados. Em grandes instalações, não é incomum ver servidores de aplicativos ultrapassando os servidores de banco de dados por um fator de 10 a 1 ou mais. Adicionar mais servidores de aplicativos geralmente é uma questão simples de clonar um servidor existente em um novo hardware. A adição de novos servidores de banco de dados, por outro lado, é dramaticamente mais difícil na maioria dos casos.

Então, neste ponto, o mantra se torna proteger o banco de dados . Acontece que, ao armazenar em cache os resultados do banco de dados em memcached ou ao enfileirar atualizações em um log do lado do aplicativo, ou ao buscar os dados uma vez e calcular suas estatísticas no aplicativo, você pode reduzir drasticamente a carga de trabalho do banco de dados, evitando que para recorrer a uma configuração de cluster de banco de dados ainda mais complicada e frágil.

    
por 23.10.2012 / 20:15
fonte
11

Acho que seria um design inadequado não usar o banco de dados para as coisas para as quais ele é destinado. Eu nunca vi nenhum banco de dados onde as regras foram aplicadas fora do banco de dados que tinha bons dados. E eu olhei centenas de bancos de dados.

Então, coisas que devem ser feitas em um banco de dados:

  • Auditoria (a auditoria somente do aplicativo não rastreará todas as alterações no banco de dados e, portanto, é inútil).

  • Restrições de ingeridade de dados, incluindo valores padrão, chave estrangeira restrições e regras que devem sempre ser aplicadas a todos os dados. Todos os dados nem sempre são alterados ou inseridos por meio de um aplicativo, são correções de dados únicas, especialmente de grandes conjuntos de dados que não são É prático fazer um registro de cada vez (atualize estes 100.000 registros que foram identificados como status 1 quando deveriam ser 2 devido a um bug no código do aplicativo ou atualize todos os registros do cliente A para cliente B porque a empresa B comprou a empresa A) e as importações de dados e outros aplicativos que podem tocar no mesmo banco de dados.

  • JOINS e where clause filtering (para reduzir o número de registros enviados pela rede)

por 11.11.2012 / 13:54
fonte
5

"Premature optimization is the root of all evil (most of it, anyway) in computer programming" - Donald Knuth

O banco de dados é exatamente isso; a camada de dados do seu aplicativo. Sua tarefa é fornecer ao aplicativo os dados solicitados e armazenar os dados fornecidos a ele. Seu aplicativo é o lugar para colocar o código que realmente funciona com os dados; exibindo, validando, etc.

Enquanto o sentimento na linha do título é admirável, e precisa de um ponto (o âmago da questão de filtragem, projeção, agrupamento, etc deve no grande número de casos ser deixado para o DB) , uma definição de "bem" pode estar em ordem. As tarefas que o SQL Server pode executar com um alto nível de desempenho são muitas, mas as tarefas que você pode demonstrar que o SQL Server faz corretamente de maneira isolada e repetitiva são muito poucas. O SQL Management Studio é um excelente IDE de banco de dados (especialmente considerando as outras opções com as quais trabalhei, como TOAD), mas tem suas limitações, sendo que praticamente tudo o que você usa para fazer (ou qualquer código de procedimento executado) o DB embaixo) é, por definição, um "efeito colateral" (alterando o estado fora do domínio do espaço de memória do seu processo). Além disso, o código procedural no SQL Server é apenas agora, com os IDEs e ferramentas mais recentes, capaz de medir a maneira como o código gerenciado pode usar métricas de cobertura e análise de caminho (para demonstrar que essa instrução if é encontrada pelos testes X , Y e Z, e o teste X foi projetado para tornar a condição verdadeira e executar essa metade enquanto Y e Z executam o "else". Isso, por sua vez, pressupõe que você tenha um teste que pode definir o banco de dados com state, execute o código processual do banco de dados por meio de alguma ação e declare os resultados esperados.

Tudo isso é muito mais difícil e envolvido do que a solução fornecida pela maioria das camadas de acesso a dados; suponha que a camada de dados (e, nesse caso, o DAL) saiba como fazer seu trabalho quando receber a entrada correta e, em seguida, teste se o seu código fornece a entrada correta. Mantendo o código procedural como SPs e triggers fora do DB e, em vez disso, fazendo esses tipos de coisas no código do aplicativo, o código do aplicativo é muito mais fácil de se exercitar.

    
por 23.10.2012 / 19:28
fonte
5

Uma das coisas que as pessoas não parecem perceber é que fazer todo o seu processamento no servidor SQL não é necessariamente bom, independentemente dos efeitos na qualidade do código.

Por exemplo, se você precisar pegar alguns dados e, em seguida, calcular algo a partir dos dados e, em seguida, armazenar esses dados no banco de dados. Existem duas opções:

  • Pegue os dados em seu aplicativo, calcule dentro de seu aplicativo e, em seguida, envie os dados de volta ao banco de dados
  • Crie um procedimento armazenado ou similar para obter os dados, calculá-los e armazená-los de uma única chamada para o SQL Server.

Você pode pensar que a segunda solução é sempre a mais rápida, mas isso definitivamente não é verdade. Eu estou ignorando mesmo se o SQL é um ajuste ruim para o problema (ou seja, regex e manipulação de string). Vamos fingir que você tem SQL CLR ou algo semelhante para ter uma linguagem poderosa no banco de dados mesmo. Se levar 1 segundo para fazer uma viagem de ida e volta, obter os dados e 1 segundo para armazená-los e, em seguida, 10 segundos para fazer o cálculo através dele. Você está fazendo errado se estiver fazendo tudo no banco de dados.

Claro, você raspa 2 segundos. No entanto, você prefere desperdiçar 100% de (pelo menos) um núcleo de CPU em seu servidor de banco de dados por 10 segundos, ou prefere perder esse tempo em seu servidor web?

Os servidores Web são fáceis de escalar, os bancos de dados, por outro lado, são extremamente caros, especialmente os bancos de dados SQL. Na maioria das vezes, os servidores da Web também são "sem estado" e podem ser adicionados e removidos por capricho, sem nenhuma configuração adicional, exceto o balanceador de carga.

Então, pense não apenas em cortar 2 segundos em uma operação, mas também em dimensionar. Por que desperdiçar um recurso caro, como recursos de servidor de banco de dados, quando você pode usar os recursos muito mais baratos do servidor da Web com um impacto de desempenho relativamente pequeno

    
por 26.10.2012 / 19:53
fonte
4

Eu gosto de ver como o SQL deve lidar apenas com os dados em si. As regras de negócios que decidem a aparência da consulta podem acontecer no código. A regex ou validação da informação deve ser feita em código. O SQL deve ser deixado apenas para entrar na sua tabela, consultar seus dados, inserir dados limpos, etc.

O que é passado para o SQL deve ser limpo e o SQL não precisa realmente saber nada mais do que o necessário para armazená-lo, atualizá-lo, excluí-lo ou recuperar algo. Eu vi muitos desenvolvedores querem lançar sua lógica de negócios e codificação em SQL porque eles pensam nos dados como seus negócios. Desacople sua lógica dos dados e você verá que seu código fica mais limpo e fácil de gerenciar.

Apenas meus US $ 0,02.

    
por 23.10.2012 / 18:14
fonte
3

Geralmente, concordo que o código deve controlar a lógica de negócios e o banco de dados deve ser um hash livre de lógica. Mas aqui estão alguns contra-pontos:

As restrições primárias, chaves estrangeiras e obrigatórias (não nulas) podem ser impostas pelo código. Restrições são lógica de negócios. Eles devem ser deixados de fora do banco de dados, uma vez que duplicam o que o código pode fazer?

Outras partes fora do seu controle tocam no banco de dados? Se assim for, ter restrições impostas perto dos dados é bom. O acesso pode ser restrito a um serviço da web que implemente lógica, mas isso pressupõe que você estava lá "em primeiro lugar" e tem o poder de impor o uso do serviço às outras partes.

O seu ORM realiza uma inserção / atualização separada para cada objeto? Se sim, você terá sérios problemas de desempenho quando processar lotes grandes conjuntos de dados. Definir operações é o caminho a percorrer. Um ORM terá problemas para modelar com precisão todos os conjuntos possíveis que você poderia realizar operações.

Você considera uma "camada" uma divisão física por servidores ou uma divisão lógica? A lógica de execução em qualquer servidor poderia, teoricamente, ainda estar sob sua camada lógica. Você pode organizar a divisão compilando em DLLs diferentes em vez de dividir servidores exclusivamente. Isso pode aumentar drasticamente o tempo de resposta (mas sacrificando a produtividade), mantendo a separação de interesses. Uma DLL dividida pode ser movida posteriormente para outros servidores sem uma nova compilação para aumentar o rendimento (ao custo do tempo de resposta).

    
por 23.10.2012 / 18:26
fonte
3

O idioma tem mais a ver com manter as regras de negócios, fazer com os dados, juntamente com as relações (os dados, a estrutura e os relacionamentos.) Não é um balcão único para todos os problemas, mas ajuda a evitar coisas como contadores de registros mantidos manualmente, integridade de relacionamento mantida manualmente, etc., se essas coisas estiverem disponíveis no nível do banco de dados. Então, se alguém aparecer e estender os programas ou escrever outro programa que interaja com o banco de dados, eles não precisarão descobrir como manter a integridade do banco de dados a partir do código anterior. O caso de um contador de registros mantido manualmente é particularmente pertinente quando alguém deseja criar um novo programa para interagir com o mesmo banco de dados. Mesmo que o programa recém-criado tenha exatamente o código correto para o contador, o programa original e o novo programa executado aproximadamente ao mesmo tempo provavelmente o corromperão. Há até um código lá fora que recupera registros e verifica as condições antes de gravar um registro novo ou atualizado (no código ou como consultas separadas), quando, se possível, isso pode ser obtido diretamente na instrução insert ou update. Corrupção de dados pode resultar novamente. O mecanismo de banco de dados garante atomicidade; É garantido que uma consulta de atualização ou inserção com condições afeta apenas os registros que atendem às condições e nenhuma consulta externa pode alterar os dados na metade da nossa atualização. Há muitas outras circunstâncias em que o código é usado quando o mecanismo de banco de dados seria melhor exibido. É tudo sobre integridade de dados e não sobre desempenho.

Então, na verdade, é uma boa linguagem de design ou regra de ouro. Nenhuma quantidade de desempenho ajudará em um sistema com dados corrompidos.

    
por 24.10.2012 / 01:08
fonte
0

Como mencionado anteriormente, o objetivo é enviar e receber o mínimo possível do banco de dados, pois as viagens de ida e volta são muito dispendiosas em termos de tempo. Enviar instruções SQL repetidas vezes é uma perda de tempo, especialmente em consultas mais complexas.

O uso de procedimentos armazenados no banco de dados permite que os desenvolvedores interajam com o banco de dados como uma API, sem se preocupar com o esquema complexo na parte de trás. Também reduz os dados enviados para o servidor, pois apenas o nome e alguns parâmetros são enviados. Nesse cenário, a maior parte da lógica do negócio ainda pode estar no código, mas não na forma de SQL. O código essencialmente prepararia o que deve ser enviado ou solicitado do banco de dados.

    
por 24.10.2012 / 02:02
fonte
0

Há algumas coisas para lembrar:

  • Um banco de dados relacional deve garantir a integridade referencial por meio de chaves estrangeiras
  • O dimensionamento de um banco de dados pode ser difícil e caro. Escalar um servidor web é muito mais fácil simplesmente adicionando mais servidores web. Divirta-se tentando adicionar mais poder do servidor SQL.
  • Com C # e LINQ, você pode fazer suas "junções" e assim por meio do código, para que você obtenha o melhor dos dois mundos em muitos casos
por 25.10.2012 / 03:56
fonte
0

"Premature optimization is the root of all evil" - Donald Knuth

Use a ferramenta mais apropriada para o trabalho. Para integridade de dados, esse é frequentemente o banco de dados. Para regras de negócios avançadas, este é um sistema baseado em regras, como o JBoss Drools. Para visualização de dados, isso seria uma estrutura de relatório. etc.

Se você tiver algum problema de desempenho, deverá verificar se algum dado pode ser armazenado em cache ou se uma implementação no banco de dados seria mais rápida. Em geral, o custo de comprar servidores extras ou energia adicional na nuvem será muito menor do que o custo de manutenção adicional e o impacto de bugs extras.

    
por 02.02.2014 / 02:04
fonte