Ho due tabelle in un database MySQL 5.7.22: posts
e reasons
. Ogni riga del post ha e appartiene a molte righe del motivo. Ogni motivo ha un peso associato ad esso e ogni post ha quindi un peso totale aggregato ad esso associato.
Per ogni incremento di 10 punti di peso (cioè per 0, 10, 20, 30, ecc.), Voglio ottenere un conteggio di post che abbiano un peso totale inferiore o uguale a quell'incremento. Mi aspetto che i risultati siano simili a questi:
weight | post_count
--------+------------
0 | 0
10 | 5
20 | 12
30 | 18
... | ...
280 | 20918
290 | 21102
... | ...
1250 | 118005
1260 | 118039
1270 | 118040
I pesi totali sono approssimativamente distribuiti normalmente, con pochi valori molto bassi e pochi valori molto alti (il massimo è attualmente 1277), ma la maggior parte nel mezzo. Ci sono poco meno di 120.000 file dentro posts
e circa 120 pollici reasons
. Ogni post ha in media 5 o 6 motivi.
Le parti pertinenti delle tabelle sono simili alle seguenti:
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)
);
Finora, ho provato a far cadere l'ID del post e il peso totale in una vista, quindi unendo quella vista a se stessa per ottenere un conteggio aggregato:
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;
Questo è, comunque, insolitamente lento: l'ho lasciato funzionare per 15 minuti senza interruzione, cosa che non posso fare in produzione.
C'è un modo più efficiente per farlo?
Se sei interessato a testare l'intero set di dati, è scaricabile qui . Il file è di circa 60 MB, si espande a circa 250 MB. In alternativa, ci sono 12.000 righe in una sintesi di GitHub qui .
w.weight
- giusto? Sto cercando di contare i post con un peso totale (somma dei pesi delle righe dei motivi associati) di ltew.weight
.