shopkeeper
A tabela possui os seguintes campos:
id (bigint),amount (numeric(19,2)),createddate (timestamp)
Digamos, eu tenho a tabela acima. Quero obter os registros de ontem e gerar um relatório imprimindo o valor em centavos.
Uma maneira de fazer é realizar cálculos no meu aplicativo java e executar uma consulta simples
Date previousDate ;// $1 calculate in application
Date todayDate;// $2 calculate in application
select amount where createddate between $1 and $2
e depois percorrer os registros e converter o valor em centavos no meu aplicativo java e gerar o relatório
Outra maneira é como realizar cálculos na própria consulta sql:
select cast(amount * 100 as int) as "Cents"
from shopkeeper where createddate between date_trunc('day', now()) - interval '1 day' and date_trunc('day', now())
e depois percorrer os registros e gerar o relatório
De uma maneira, todo o meu processamento é feito no aplicativo java e uma consulta simples é acionada. Em outro caso, todas as conversões e cálculos são feitos na consulta SQL.
O caso de uso acima é apenas um exemplo, em um cenário real, uma tabela pode ter muitas colunas que requerem processamento do tipo semelhante.
Você pode me dizer qual abordagem é melhor em termos de desempenho e outros aspectos e por quê?
fonte
Respostas:
Depende de muitos fatores - mas o mais importante:
Como sempre, se você faz trazer a volta de dados para o aplicativo-servidor, minimizando as colunas e linhas será a sua vantagem. Certificar-se de que a consulta esteja ajustada e indexada adequadamente ajudará em ambos os cenários.
Re sua nota:
Fazer loop nos registros é quase sempre a coisa errada a se fazer no sql - escrever uma operação baseada em conjunto é o preferido.
Como regra geral , prefiro manter o trabalho do banco de dados no mínimo "armazene esses dados, busque esses dados" - no entanto, sempre existem exemplos de cenários em que uma consulta elegante no servidor pode economizar muita largura de banda.
Considere também: se isso é computacionalmente caro, pode ser armazenado em cache em algum lugar?
Se você quer um "melhor" preciso ; codifique-o nos dois sentidos e compare-o (observando que um primeiro rascunho de um dos dois provavelmente não está 100% sintonizado). Mas considere o uso típico disso: se, na realidade, ele estiver sendo chamado 5 vezes (separadamente) de uma só vez, simule o seguinte: não compare apenas um único "1 destes versus 1 deles".
fonte
Deixe-me usar uma metáfora: se você quiser comprar um colar de ouro em Paris, o ourives poderia sentar-se na Cidade do Cabo ou Paris, isso é uma questão de habilidade e bom gosto. Mas você nunca enviaria toneladas de minério de ouro da África do Sul para a França para isso. O minério é processado no local de mineração (ou pelo menos na área geral), apenas o ouro é enviado. O mesmo deve ser verdade para aplicativos e bancos de dados.
No que diz respeito ao PostgreSQL , você pode fazer quase tudo no servidor, com bastante eficiência. O RDBMS é excelente em consultas complexas. Para necessidades processuais, você pode escolher entre uma variedade de linguagens de script do lado do servidor : tcl, python, perl e muito mais. Principalmente eu uso PL / pgSQL , no entanto.
O pior cenário seria ir repetidamente ao servidor para todas as linhas de um conjunto maior. (Seria como transportar uma tonelada de minério por vez.)
Segundo na fila , se você enviar uma cascata de consultas, cada uma dependendo da anterior, enquanto tudo isso poderá ser feito em uma consulta ou procedimento no servidor. (É como enviar o ouro e cada uma das jóias com um navio separado, sequencialmente.)
Ir e voltar entre o aplicativo e o servidor é caro. Para servidor e cliente. Tente reduzir isso e você ganhará: os procedimentos do servidor e / ou SQL sofisticado, quando necessário.
Acabamos de terminar um projeto em que empacotamos quase todas as consultas complexas nas funções do Postgres. O aplicativo entrega parâmetros e obtém os conjuntos de dados necessários. Rápido, limpo, simples (para o desenvolvedor de aplicativos), a E / S reduziu ao mínimo ... um colar brilhante com uma pegada de baixo carbono.
fonte
Nesse caso, você provavelmente está um pouco melhor fazendo o cálculo no SQL, pois o mecanismo do banco de dados provavelmente possui rotinas aritméticas decimais mais eficientes do que o Java.
Geralmente, porém, para cálculos no nível da linha, não há muita diferença.
O que faz a diferença é:
fonte
Não há preto / branco com relação a quais partes da lógica de acesso a dados devem ser executadas no SQL e quais partes devem ser executadas em seu aplicativo. Eu gosto da redação de Mark Gravell , distinguindo entre
O poder e a expressividade do SQL são muito subestimados. Desde a introdução das funções da janela , muitos cálculos não estritamente orientados a conjuntos podem ser executados com muita facilidade e elegância no banco de dados.
Três regras práticas devem sempre ser seguidas, independentemente da arquitetura geral do aplicativo:
Na minha experiência, com um DBA decente e algum conhecimento decente sobre seu banco de dados decente, você não encontrará os limites de CPU dos seus DBs em breve.
Algumas leituras adicionais onde estas coisas são explicadas:
fonte
Em geral, faça coisas no SQL se houver chances de que também outros módulos ou componentes no mesmo ou em outros projetos precisem obter esses resultados. uma operação atômica realizada do lado do servidor também é melhor porque você só precisa chamar o processo armazenado de qualquer ferramenta de gerenciamento de banco de dados para obter valores finais sem processamento adicional.
Em alguns casos, isso não se aplica, mas quando isso faz sentido. também, em geral, a caixa db tem os melhores desempenhos e hardware.
fonte
Se você estiver escrevendo sobre ORM ou escrevendo aplicativos casuais de baixo desempenho, use qualquer padrão que simplifique o aplicativo. Se você estiver escrevendo um aplicativo de alto desempenho e pensando cuidadosamente sobre a escala, vencerá movendo o processamento para os dados. Eu defendo fortemente a mudança do processamento para os dados.
Vamos pensar sobre isso em duas etapas: (1) transações OLTP (pequeno número de registros). (2) OLAP (varreduras longas de muitos registros).
No caso OLTP, se você quiser ser rápido (transações de 10 a 100k por segundo), deverá remover a contenção de trava, bloqueio e bloqueio morto do banco de dados. Isso significa que você precisa eliminar longas paradas nas transações: as viagens de ida e volta do cliente para o DB para mover o processamento para o cliente são uma dessas longas paradas. Você não pode ter transações de longa duração (para tornar a leitura / atualização atômica) e ter uma taxa de transferência muito alta.
Re: escala horizontal. Os bancos de dados modernos são dimensionados horizontalmente. Esses sistemas já implementam tolerância a HA e falhas. Aproveite isso e tente simplificar o espaço do aplicativo.
Vejamos o OLAP - nesse caso, deve ser óbvio que arrastar possivelmente terrabytes de dados de volta para o aplicativo é uma ideia horrível. Esses sistemas são construídos especificamente para operar de maneira extremamente eficiente com dados colunares compactados e pré-organizados. Os sistemas OLAP modernos também são dimensionados horizontalmente e possuem planejadores de consultas sofisticados que dispersam o trabalho horizontalmente (movendo internamente o processamento para os dados).
fonte
A decisão de realizar cálculos no front-end ou no back-end é muito decidida se podemos determinar nosso objetivo na implementação do negócio. No momento, o código java pode ter um desempenho melhor do que um código sql bem escrito ou pode ser vice-versa. Mas ainda assim, se confuso, você pode tentar determinar primeiro -
Existem muitos outros aspectos que você pode pensar antes de decidir onde colocar o código. Uma percepção está totalmente errada - tudo pode ser feito melhor em Java (código do aplicativo) e / ou tudo deve ser feito pelo db (código sql).
fonte
Formar um ponto de vista de desempenho: Essa é uma operação aritmética muito simples que quase certamente pode ser executada muito mais rapidamente do que a busca de dados dos discos subjacentes ao banco de dados. Além disso, é provável que o cálculo dos valores na cláusula where seja muito rápido em qualquer tempo de execução. Em resumo, o gargalo deve ser E / S de disco, não o cálculo dos valores.
De acordo com a legibilidade, acho que se você usa um ORM, deve fazê-lo no ambiente do servidor de aplicativos, porque o ORM permitirá trabalhar com os dados subjacentes com muita facilidade, usando operações baseadas em conjunto. Se você for escrever SQL bruto de qualquer maneira, não há nada errado em fazer a computação lá, seu SQL também pareceria um pouco melhor e mais fácil de ler se formatado corretamente.
fonte
Fundamentalmente, "desempenho" não está definido.
O que mais importa para mim é o tempo do desenvolvedor.
Escreva a consulta SQL. Se estiver muito lento ou o banco de dados se tornar um gargalo, reconsidere. Nesse momento, você poderá comparar as duas abordagens e tomar sua decisão com base em dados reais relevantes para sua configuração (hardware e qualquer pilha em que estiver).
fonte
Não acredito que as diferenças de desempenho possam ser justificadas sem exemplos e referências específicas, mas tenho outra opinião:
Qual você pode manter melhor? Por exemplo, convém alternar seu front-end de Java para Flash, HTML5, C ++ ou qualquer outra coisa. Um grande número de programas passou por essa mudança ou até existe em mais de um idioma, porque eles precisam trabalhar em vários dispositivos.
Mesmo se você tiver uma camada intermediária adequada (a partir do exemplo dado, parece que não é o caso), essa camada poderá mudar e o JBoss poderá se tornar Ruby / Rails.
Por outro lado, é improvável que você substitua o back-end do SQL por algo que não seja um banco de dados relacional com o SQL e, se o fizer, terá que reescrever o front-end do zero de qualquer maneira, para que o ponto seja discutível.
Minha idéia é que, se você fizer cálculos no banco de dados, será muito mais fácil escrever um segundo front-end ou camada intermediária posteriormente, porque você não precisará reimplementar tudo. Na prática, porém, acho que "onde posso fazer isso com código que as pessoas entenderão" é o fator mais importante.
fonte
Simplificar como responder a isso seria examinar o balanceamento de carga. Você deseja colocar a carga onde tiver mais capacidade (se isso fizer algum sentido). Na maioria dos sistemas, é o servidor SQL que rapidamente se torna um gargalo; portanto, a resposta provável é que você não deseja que o SQL faça mais um trabalho do que o necessário.
Também na maioria das arquiteturas, são os servidores SQL que compõem o núcleo do sistema e os sistemas externos que são adicionados.
Mas a matemática acima é tão trivial que, a menos que você esteja levando o sistema ao limite, o melhor lugar para colocá-lo é onde você deseja colocá-lo. Se a matemática não fosse trivial, como calcular sin / cos / tan, por exemplo, um cálculo à distância, o esforço pode se tornar não trivial e exigir planejamento e testes cuidadosos.
fonte
As outras respostas a esta pergunta são interessantes. Surpreendentemente, ninguém respondeu à sua pergunta. Você está se perguntando:
Mais informações: Para a pergunta um, você deseja ter certeza de que a agregação das frações funciona sem erros de arredondamento. Acho que o numérico 19,2 é razoável por dinheiro e, no segundo caso, os números inteiros estão OK. Usar um carro alegórico por dinheiro está errado por esse motivo.
Para a pergunta dois, eu gosto de ter controle total como programador de que data é considerada "agora". Pode ser difícil escrever testes de unidade automáticos ao usar funções como agora (). Além disso, quando você tem um script de transação mais longo, pode ser bom definir uma variável igual a now () e usar a variável para que toda a lógica use exatamente o mesmo valor.
fonte
Deixe-me dar um exemplo real para resolver esta questão
Eu precisava calcular uma média móvel ponderada nos meus dados ohlc, tenho cerca de 134000 velas com um símbolo para cada um fazer isso
Qual é o melhor?
Exigências
Para dar algum incentivo, esta é a versão do Python para fazer uma média móvel ponderada
WMA feito através do código
WMA através do SQL
Acredite ou não, a consulta é executada mais rapidamente do que a versão Pure Python de fazer uma MÉDIA EM MOVIMENTO PESADO !!! Eu fui passo a passo para escrever essa consulta, então aguente firme e você vai se sair bem
Rapidez
0.42141127300055814 segundos Python
0.23801879299935536 segundos SQL
Eu tenho 134000 registros OHLC falsos no meu banco de dados, divididos entre 1000 ações. Esse é um exemplo de onde o SQL pode superar o servidor de aplicativos
fonte