Вычисление среднего из последних N записей таблицы - PullRequest
0 голосов
/ 02 ноября 2019

У меня есть таблица MySQL, в которой хранятся данные о ценах некоторых компаний:

| Field            | Type          | Null | Key | Default | Extra          |
| id               | bigint(20)    | NO   | PRI | NULL    | auto_increment |
| company_id       | int(11)       | NO   |     | NULL    |                |
| company_name     | varchar(200)  | YES  |     | NULL    |                |
| time_stamp       | datetime      | YES  |     | NULL    |                |
| date             | datetime      | YES  |     | NULL    |                |
| shamsi_date      | varchar(12)   | YES  |     | NULL    |                |
| final_price      | decimal(10,3) | YES  |     | NULL    |                |

Версия MySQL: 8.0.14

Есть 2048 идентификаторов компаний, а данные о ценахобновляется ежедневно. Я хочу выполнить следующие шаги:

  1. Получить последние N цен каждой компании. N равно 30. Но у некоторых компаний может быть меньше данных, т.е. за 18 дней или 23 дня,

  2. Расчет среднего значения этих цен для каждой компании,

  3. и, наконец, поместите его в другую строку другой таблицы.

Я написал для этого следующий код:

public HashMap<Long, Double> getMeanVolume() {

    HashMap<Long, Double> volumeList = new HashMap<Long, Double>();

    double sum = 0;

    int pageSize = 30;


    CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

    CriteriaQuery<DailyEntity> criteriaQuery = criteriaBuilder.createQuery(DailyEntity.class);

    Root<DailyEntity> root = criteriaQuery.from(DailyEntity.class);

    criteriaQuery = criteriaQuery.select(root);

    // Sorting
    criteriaQuery.orderBy(criteriaBuilder.desc(root.get("shamsiDate")));

    ArrayList<Long> list = new ArrayList<>();
    list = getCompanyID();

    for (Long com_id : list) {

        sum = 0;

        // Selecting
        Predicate predicate = criteriaBuilder.equal(root.get("companyID"), com_id);
        criteriaQuery.where(predicate);

        // Now everything should be gathered together in a TypedQuery:
        TypedQuery<DailyEntity> typedQuery = em.createQuery(criteriaQuery);

        // Pagination settings
        typedQuery.setFirstResult(0);
        typedQuery.setMaxResults(pageSize);

        // Getting Results. Here as we have Payment as the root element, we have
        // can get a list of Payments.
        List<DailyEntity> results = typedQuery.getResultList();

        if (results.isEmpty())
            continue;

        for (DailyEntity entit : results) {

            sum += entit.getLegal().getNaturalSellVol() + entit.getLegal().getLegalSellVol();

        }
        volumeList.put(com_id.longValue(), sum / results.size());
        log.info(com_id.toString());

    }

    // volumeList.forEach((key, value) -> {System.out.println(key + " " + value);});

    return volumeList;

}

Этот код работает, но оночень медленноРасчет каждого среднего занимает около 0,6 секунд.

  1. Можно ли выполнить этот расчет с некоторыми запросами SQL. Я думаю, что это будет быстрее.

  2. Как я могу улучшить этот код?

1 Ответ

0 голосов
/ 13 ноября 2019

Попробуйте в вашем хранилище

@Query("SELECT AVG(final_price)  FROM (SELECT final_price FROM companies ORDER BY company_id DESC LIMIT ?1)")
Double getAverageOfLastNRecords(int n);
...