У меня есть две таблицы в базе данных MySQL 5.7.22: posts
и reasons
. Каждая строка сообщения имеет и принадлежит многим рядам причин. У каждой причины есть вес, связанный с ней, и поэтому у каждого сообщения есть общий агрегированный вес, связанный с ним.
Для каждого увеличения веса на 10 пунктов (т. Е. Для 0, 10, 20, 30 и т. Д.) Я хочу получить количество сообщений, общий вес которых меньше или равен этому приращению. Я ожидаю, что результаты для этого будут выглядеть примерно так:
weight | post_count
--------+------------
0 | 0
10 | 5
20 | 12
30 | 18
... | ...
280 | 20918
290 | 21102
... | ...
1250 | 118005
1260 | 118039
1270 | 118040
Полные веса примерно нормально распределены, с несколькими очень низкими значениями и несколькими очень высокими значениями (максимальный в настоящее время 1277), но большинство в середине. Есть чуть менее 120000 строк posts
и около 120 дюймов reasons
. Каждый пост имеет в среднем 5 или 6 причин.
Соответствующие части таблиц выглядят так:
CREATE TABLE `posts` (
id BIGINT PRIMARY KEY
);
CREATE TABLE `reasons` (
id BIGINT PRIMARY KEY,
weight INT(11) NOT NULL
);
CREATE TABLE `posts_reasons` (
post_id BIGINT NOT NULL,
reason_id BIGINT NOT NULL,
CONSTRAINT fk_posts_reasons_posts (post_id) REFERENCES posts(id),
CONSTRAINT fk_posts_reasons_reasons (reason_id) REFERENCES reasons(id)
);
До сих пор я пытался сбросить идентификатор сообщения и общий вес в представление, а затем соединить это представление с самим собой, чтобы получить агрегированное число:
CREATE VIEW `post_weights` AS (
SELECT
posts.id,
SUM(reasons.weight) AS reason_weight
FROM posts
INNER JOIN posts_reasons ON posts.id = posts_reasons.post_id
INNER JOIN reasons ON posts_reasons.reason_id = reasons.id
GROUP BY posts.id
);
SELECT
FLOOR(p1.reason_weight / 10) AS weight,
COUNT(DISTINCT p2.id) AS cumulative
FROM post_weights AS p1
INNER JOIN post_weights AS p2 ON FLOOR(p2.reason_weight / 10) <= FLOOR(p1.reason_weight / 10)
GROUP BY FLOOR(p1.reason_weight / 10)
ORDER BY FLOOR(p1.reason_weight / 10) ASC;
Это, однако, необычайно медленно - я позволил ему работать в течение 15 минут без остановки, что я не могу сделать в производстве.
Есть ли более эффективный способ сделать это?
Если вы заинтересованы в тестировании всего набора данных, его можно загрузить здесь . Размер файла составляет около 60 МБ, он увеличивается до 250 МБ. С другой стороны , есть 12000 строк в сущности GitHub здесь .
w.weight
- это правильно? Я рассчитываю подсчитывать сообщения с общим весом (суммой весов связанных с ними строк причин) ltew.weight
.