Há uma tabela onde estão as taxas de câmbio.
fx_rates
---
id
buy_curr_code
sell_curr_code
rate
inserted_at
Uma tabela é atualizada com frequência desconhecida: às vezes diariamente, às vezes várias vezes ao dia, às vezes uma vez em vários dias. O mesmo vale para as moedas: algumas podem ser atualizadas desta vez, outras no outro.
E os dados nunca são excluídos da tabela, mas apenas inseridos ou atualizados.
Como consultarei as taxas de câmbio mais recentes e atualizadas dele? Ou seja, uma única taxa de câmbio por cada buy - sell currency_code
par único.
Devo usar distinct
e se sim, como?
A resposta de Erwin está correta, mas a consulta ficará cada vez mais lenta conforme a tabela cresce. Então deixe-me sugerir um modelo de dados diferente:
Adicione uma coluna
active
do tipoboolean
TRUE para a entrada mais recente por(buy_curr_code, sell_curr_code)
.Então você adicionaria um índice:
Para inserir uma nova linha, você executaria esta transação:
O bom dessa solução é que agora é fácil consultar as entradas ativas e o desempenho dessa consulta será independente do tamanho da tabela.
Para limpar os dados, você pode particionar a tabela por lista
active
e subparticionar a partição FALSE por intervalo de tempo.DISTINCT ON
é uma das maneiras mais simples:Tenha um índice
(buy_curr_code, sell_curr_code, inserted_at DESC)
para tornar isso rápido. Ver:Se houver muitas linhas por
(buy_curr_code, sell_curr_code)
- o que parece provável - outras técnicas de consulta serão mais rápidas. As especificidades dependem de detalhes não revelados. Ver:Melhor design
Se alterar o design do banco de dados for uma opção, eu consideraria uma tabela adicional com uma única entrada por conversão. Como:
E dispara
ON INSERT
eON UPDATE
insere uma nova entrada de "log" na tabelafx_rates
. Todas as novas entradas são atualizações paracurrent_rate
. Somente o gatilho grava na tabelafx_rates
. (O gatilho pode executar verificações adicionais.)INSERT
acionar:Demonstração completa neste violino .
Então o conteúdo de
current_rate
é sempre o resultado pronto que você tentou gerar.Por que?
Cada abordagem tem prós e contras. O único requisito declarado é a lista de taxas atuais. Minha solução fornece isso
SELECT * FROM current_rate
- o mais simples e rápido possível. Adicionar uma nova taxa é um único arquivoUPDATE
. Armazenamento:fx_rates
é ordem de grandeza maior quecurrent_rate
. Não precisamos de nenhum índice naquela grande mesa. É efetivamenteINSERT
apenas, portanto, nenhuma tabela e índice incham. Podemos tornar a tabela grande ainda menor adicionando umaIDENTITY
coluna inteira como substituto PK paracurrent_rate
, e apenas escrever este ID de 4 bytes parafx_rates
. Na verdade, nada em sua pergunta diz que ainda precisamos,fx_rates
uma vez que temoscurrent_rates
. (Mas eu esperaria que houvesse propósitos adicionais.)A única sofisticação moderada é o gatilho, que também é muito simples. Portanto, a menos que você tenha outros requisitos, o design sugerido é mais simples, rápido, menor e mais confiável.
Uma terceira alternativa que funciona muito bem em termos de desempenho e não exige que você altere o esquema da tabela, é usar uma função de janela como
ROW_NUMBER()
. Isso permite que você enumere as linhas dentro de cada grupo debuy_curr_code, sell_curr_code
pares e, em seguida, selecione apenas a última linha por grupo da seguinte forma:Você provavelmente deseja um índice
(buy_curr_code, sell_curr_code, inserted_at, id)
para tornar isso mais eficiente.A razão
id
é adicionada ao final daORDER BY
cláusula naROW_NUMBER()
expressão é para a chance de duas linhas serem inseridas exatamente ao mesmoinserted_at
tempo, então aquela com a últimaid
(idealmente a linha que realmente veio por último) é o desempate, para garantir que aORDER BY
cláusula seja determinística.As funções de janela são ferramentas muito úteis para fazer cálculos e manipular os dados.