Melhores práticas para o cálculo da classificação geral

Eu tenho o aplicativo de negócios baseado em LAMP. SugarCRM para ser mais preciso. Existem mais de 120 usuários ativos no momento. Todos os dias, cada usuário gera alguns registros que são usados ​​em cálculos complexos para obter a chamada “classificação individual”.

Demora cerca de 6 segundos para calcular um valor de "classificação individual". E não havia um grande problema antes: cada usuário acessa o link fornecido para iniciar os cálculos de "classificação individual", aguarda por 6 a 7 segundos e obtém o valor exibido.

Mas agora preciso implementar o cálculo da "classificação geral". Isso significa que, além de “classificação individual”, preciso calcular e exibir para o usuário:

  • avaliação individual mínima entre TODOS os usuários do aplicativo

  • avaliação individual máxima entre TODOS os usuários do aplicativo

  • posição atual do usuário no intervalo de todas as avaliações individuais.

Digamos que o usuário atual tenha uma classificação individual igual a 220 pontos, o valor mínimo de classificação é 80, o máximo é 235 e ele está na 23ª posição entre todos os usuários.

Quais são os principais problemas a serem resolvidos?

  1. Se um cálculo tiver a duração de 6 segundos, os cálculos gerais levarão mais de 10 minutos. Acho que não é bom tornar o aplicativo quase inacessível para esse período. E se a quantidade de usuários subir no futuro próximo de 2 a 3 vezes?

  2. Esses cálculos podem ser feitos como trabalho noturno, mas todos os usuários estão em fusos horários diferentes. Na Rússia, a diferença entre fusos horários extremos é de 9 horas. Então as pessoas na parte oeste da Rússia ainda estão trabalhando em “hoje”. Enquanto as pessoas na parte oriental estão acordando para trabalhar em “amanhã”. Então, qual é o melhor momento para o trabalho noturno neste caso?

Existem melhores práticas | abordagens | algoritmos para construir esse sistema de classificação?

0
Eu acho que o principal problema é: por que deveria levar 6-7 segundos para calcular uma classificação?
adicionado o autor alzaimar, fonte
Este é principalmente o tempo de execução da consulta SQL.
adicionado o autor erop, fonte
Este é principalmente o tempo de execução da consulta SQL.
adicionado o autor erop, fonte
Este é principalmente o tempo de execução da consulta SQL.
adicionado o autor erop, fonte

6 Respostas

Considerando apenas as informações fornecidas, as únicas opções que vejo são:

  1. The obvious one - reduce the time taken for a rating calculation (6 seconds to calculate 1 user's rating seems like a lot)

  2. If possible, have intermediate values which you only recalculate some of, as required (for example, have 10 values that make up the rating, all based on different data, when some of the data changes, flag the appropriate values for recalcuation). Either do this recalculation:

    • During your daily recalculation or
    • When the update happens
  3. Partial batch calculation - only recalculate x of the users' ratings at chosen intervals (where x is some chosen value) - has the disadvantage that, at all times, some of the ratings can be out of date

  4. Calculate if not busy - either continuously recalculate ratings or only do so at a chosen interval, but instead of locking the system, have it run as a background process, only doing work if the system is idle

0
adicionado

Considerando apenas as informações fornecidas, as únicas opções que vejo são:

  1. The obvious one - reduce the time taken for a rating calculation (6 seconds to calculate 1 user's rating seems like a lot)

  2. If possible, have intermediate values which you only recalculate some of, as required (for example, have 10 values that make up the rating, all based on different data, when some of the data changes, flag the appropriate values for recalcuation). Either do this recalculation:

    • During your daily recalculation or
    • When the update happens
  3. Partial batch calculation - only recalculate x of the users' ratings at chosen intervals (where x is some chosen value) - has the disadvantage that, at all times, some of the ratings can be out of date

  4. Calculate if not busy - either continuously recalculate ratings or only do so at a chosen interval, but instead of locking the system, have it run as a background process, only doing work if the system is idle

0
adicionado

Considerando apenas as informações fornecidas, as únicas opções que vejo são:

  1. The obvious one - reduce the time taken for a rating calculation (6 seconds to calculate 1 user's rating seems like a lot)

  2. If possible, have intermediate values which you only recalculate some of, as required (for example, have 10 values that make up the rating, all based on different data, when some of the data changes, flag the appropriate values for recalcuation). Either do this recalculation:

    • During your daily recalculation or
    • When the update happens
  3. Partial batch calculation - only recalculate x of the users' ratings at chosen intervals (where x is some chosen value) - has the disadvantage that, at all times, some of the ratings can be out of date

  4. Calculate if not busy - either continuously recalculate ratings or only do so at a chosen interval, but instead of locking the system, have it run as a background process, only doing work if the system is idle

0
adicionado

(Desculpe, não consegui com postagem de comentários "longa"; por isso decidi postar como resposta)

@Dukeling

Consulta SQL que leva quase todo o tempo para o cálculo mencionado acima é apenas uma replicação da lógica de negócios que deve ser executada no código PHP. A lógica foi movida para o SQL com a esperança de reduzir o tempo de cálculo. OK, vou tentar otimizar a consulta SQL e brincar com a lógica de execução no código PHP.

Suponha que depois que o aplicativo otimizado calcule a classificação individual por apenas 1 segundo. Ótimo! Mas mesmo neste caso, o primeiro usuário logado no sistema deve esperar por 120 segundos (120 + usuários * 1 segundo = 120 segundos) para calcular a classificação geral e obter sua posição na mesma.

Estou pensando em implementar a seguinte abordagem:

  1. Let’s have 2 “overall ratings” – “today” and “yesterday”.

  2. For displaying purposes we’ll use “yesterday” overall rating represented as huge already sorted PHP array.

  3. When user hits calculation link he started “today” calculation but application displays him “yesterday” value. Thus we have quickly accessible “yesterday” rating and each user randomly launches rating calculation that will be displayed for them tomorrow.

  4. User list are partitioned by timezones. Each hour a cron job started to check if there’re any users in selected timezone that don’t have “today” individual rating calculated (e.g. user didn’t log into application). If so, application starts calculation of individual rating and puts its value in “today” (still invisible) ovarall rating array. Thus we have a cron job that runs nightly for each timezone-specific user group and fills the probable gaps in case users didn’t log into system.

  5. After all users in all timezones had been worked out, application
    1. sorts “today” array,
    2. drops “yesterday” one,
    3. rename “today” in “yesterday” and
    4. initialize new “today”.

O que você acha disso? É razoável o suficiente ou não?

0
adicionado

(Desculpe, não consegui com postagem de comentários "longa"; por isso decidi postar como resposta)

@Dukeling

Consulta SQL que leva quase todo o tempo para o cálculo mencionado acima é apenas uma replicação da lógica de negócios que deve ser executada no código PHP. A lógica foi movida para o SQL com a esperança de reduzir o tempo de cálculo. OK, vou tentar otimizar a consulta SQL e brincar com a lógica de execução no código PHP.

Suponha que depois que o aplicativo otimizado calcule a classificação individual por apenas 1 segundo. Ótimo! Mas mesmo neste caso, o primeiro usuário logado no sistema deve esperar por 120 segundos (120 + usuários * 1 segundo = 120 segundos) para calcular a classificação geral e obter sua posição na mesma.

Estou pensando em implementar a seguinte abordagem:

  1. Let’s have 2 “overall ratings” – “today” and “yesterday”.

  2. For displaying purposes we’ll use “yesterday” overall rating represented as huge already sorted PHP array.

  3. When user hits calculation link he started “today” calculation but application displays him “yesterday” value. Thus we have quickly accessible “yesterday” rating and each user randomly launches rating calculation that will be displayed for them tomorrow.

  4. User list are partitioned by timezones. Each hour a cron job started to check if there’re any users in selected timezone that don’t have “today” individual rating calculated (e.g. user didn’t log into application). If so, application starts calculation of individual rating and puts its value in “today” (still invisible) ovarall rating array. Thus we have a cron job that runs nightly for each timezone-specific user group and fills the probable gaps in case users didn’t log into system.

  5. After all users in all timezones had been worked out, application
    1. sorts “today” array,
    2. drops “yesterday” one,
    3. rename “today” in “yesterday” and
    4. initialize new “today”.

O que você acha disso? É razoável o suficiente ou não?

0
adicionado

(Desculpe, não consegui com postagem de comentários "longa"; por isso decidi postar como resposta)

@Dukeling

Consulta SQL que leva quase todo o tempo para o cálculo mencionado acima é apenas uma replicação da lógica de negócios que deve ser executada no código PHP. A lógica foi movida para o SQL com a esperança de reduzir o tempo de cálculo. OK, vou tentar otimizar a consulta SQL e brincar com a lógica de execução no código PHP.

Suponha que depois que o aplicativo otimizado calcule a classificação individual por apenas 1 segundo. Ótimo! Mas mesmo neste caso, o primeiro usuário logado no sistema deve esperar por 120 segundos (120 + usuários * 1 segundo = 120 segundos) para calcular a classificação geral e obter sua posição na mesma.

Estou pensando em implementar a seguinte abordagem:

  1. Let’s have 2 “overall ratings” – “today” and “yesterday”.

  2. For displaying purposes we’ll use “yesterday” overall rating represented as huge already sorted PHP array.

  3. When user hits calculation link he started “today” calculation but application displays him “yesterday” value. Thus we have quickly accessible “yesterday” rating and each user randomly launches rating calculation that will be displayed for them tomorrow.

  4. User list are partitioned by timezones. Each hour a cron job started to check if there’re any users in selected timezone that don’t have “today” individual rating calculated (e.g. user didn’t log into application). If so, application starts calculation of individual rating and puts its value in “today” (still invisible) ovarall rating array. Thus we have a cron job that runs nightly for each timezone-specific user group and fills the probable gaps in case users didn’t log into system.

  5. After all users in all timezones had been worked out, application
    1. sorts “today” array,
    2. drops “yesterday” one,
    3. rename “today” in “yesterday” and
    4. initialize new “today”.

O que você acha disso? É razoável o suficiente ou não?

0
adicionado