Eu tenho duas tabelas em um banco de dados MySQL 5.7.22: posts
e reasons
. Cada linha de postagem possui e pertence a muitas linhas de motivo. Cada razão tem um peso associado a ela e, portanto, cada postagem possui um peso agregado total associado a ela.
Para cada incremento de 10 pontos de peso (ou seja, para 0, 10, 20, 30, etc.), quero obter uma contagem de postagens que tenham um peso total menor ou igual a esse incremento. Eu esperaria que os resultados parecessem algo assim:
weight | post_count
--------+------------
0 | 0
10 | 5
20 | 12
30 | 18
... | ...
280 | 20918
290 | 21102
... | ...
1250 | 118005
1260 | 118039
1270 | 118040
Os pesos totais são aproximadamente distribuídos normalmente, com alguns valores muito baixos e alguns valores muito altos (o máximo é atualmente 1277), mas a maioria no meio. Existem pouco menos de 120.000 linhas posts
e cerca de 120 polegadas reasons
. Cada post tem em média 5 ou 6 razões.
As partes relevantes das tabelas são assim:
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)
);
Até agora, tentei soltar o ID da postagem e o peso total em uma visualização e associá-la a ela mesma para obter uma contagem agregada:
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;
Isso é, no entanto, inusitavelmente lento - deixei que funcionasse por 15 minutos sem terminar, o que não posso fazer na produção.
Existe uma maneira mais eficiente de fazer isso?
Caso você esteja interessado em testar o conjunto de dados inteiro, ele pode ser baixado aqui . O arquivo tem cerca de 60 MB e se expande para cerca de 250 MB. Como alternativa, existem 12.000 linhas em uma essência do GitHub aqui .
w.weight
- está certo? Estou procurando contar postagens com um peso total (soma dos pesos das linhas de razão associadas) de ltew.weight
.