Я настроил скрипку здесь: https://www.db-fiddle.com/f/snDGExYZgoYASvWkDGHKDC/2
Но также:
Схема:
CREATE TABLE `scores` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`shift_id` int unsigned NOT NULL,
`employee_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`score` double(8,2) unsigned NOT NULL,
`created_at` timestamp NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO scores(shift_id, employee_name, score, created_at) VALUES
(1, "John", 6.72, "2020-04-01 00:00:00"),
(1, "Bob", 15.71, "2020-04-01 00:00:00"),
(1, "Bob", 54.02, "2020-04-01 08:00:00"),
(1, "John", 23.55, "2020-04-01 13:00:00"),
(2, "John", 9.13, "2020-04-02 00:00:00"),
(2, "Bob", 44.76, "2020-04-02 00:00:00"),
(2, "Bob", 33.40, "2020-04-02 08:00:00"),
(2, "James", 20, "2020-04-02 00:00:00"),
(3, "John", 20, "2020-04-02 00:00:00"),
(3, "Bob", 20, "2020-04-02 00:00:00"),
(3, "Bob", 30, "2020-04-02 08:00:00"),
(3, "James", 10, "2020-04-02 00:00:00")
Запрос 1:
-- This doesn't work
SELECT
employee_name,
DATE_FORMAT(created_at, '%Y-%m-%d') AS `date`,
ANY_VALUE(AVG(score) OVER(PARTITION BY(ANY_VALUE(created_at)))) AS `average_score`
FROM
scores
GROUP BY
employee_name, date;
Запрос 2:
SELECT
employee_name,
DATE_FORMAT(created_at, '%Y-%m-%d') AS `date`,
ANY_VALUE(AVG(score)) AS `average_score`
FROM
scores
GROUP BY
employee_name, date;
Запрос 3:
-- This works but scales very poorly with millions of rows
SELECT
t1.employee_name,
ANY_VALUE(DATE_FORMAT(t1.created_at, '%Y-%m-%d')) AS `date`,
ANY_VALUE(SUM(t1.score) / (
SELECT SUM(t2.score)
FROM scores t2
WHERE date(t2.created_at) = date(t1.created_at)
) * 100) AS `average_score`
FROM
scores t1
GROUP BY
t1.employee_name, date;
Третий запрос выполняется правильно, но в моем тестировании был очень медленным при масштабировании до миллионов строк. Я думаю, это потому, что это коррелированный подзапрос, который выполняется миллионы раз.
Первые две попытки, которые я пытался создать, используют MySQL 8 оконных функций для разделения среднего вычисления. Тем не менее, они дают неожиданные результаты. Всего average_score
с за данный день должно сложиться до 100, как это происходит в 3-м запросе.
Кто-нибудь знает более эффективный способ вычисления этого?
Это также Стоит отметить, что в действительности на запросах также будет WHERE IN
для фильтрации по заданным c shift_id
с. Число shift_ids
может быть от нескольких сотен тысяч до миллиона.
Еще одна вещь, которая рассматривается, это ElasticSearch. Поможет ли это быстрее рассчитать их?