J'ai deux tables dans une base de données MySQL 5.7.22: posts
et reasons
. Chaque ligne de publication a et appartient à de nombreuses lignes de raison. Chaque raison a un poids qui lui est associé, et chaque poste a donc un poids total agrégé qui lui est associé.
Pour chaque incrément de 10 points de poids (c'est-à-dire pour 0, 10, 20, 30, etc.), je veux obtenir un nombre de messages dont le poids total est inférieur ou égal à cet incrément. Je m'attendrais à ce que les résultats ressemblent à ceci:
weight | post_count
--------+------------
0 | 0
10 | 5
20 | 12
30 | 18
... | ...
280 | 20918
290 | 21102
... | ...
1250 | 118005
1260 | 118039
1270 | 118040
Les poids totaux sont approximativement normalement distribués, avec quelques valeurs très faibles et quelques valeurs très élevées (le maximum est actuellement 1277), mais la majorité au milieu. Il y a un peu moins de 120 000 rangées posts
et environ 120 pouces reasons
. Chaque message a en moyenne 5 ou 6 raisons.
Les parties pertinentes des tableaux ressemblent à ceci:
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)
);
Jusqu'à présent, j'ai essayé de supprimer l'ID du message et le poids total dans une vue, puis de joindre cette vue à elle-même pour obtenir un nombre agrégé:
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;
C'est cependant inhabituellement lent - je l'ai laissé fonctionner pendant 15 minutes sans terminer, ce que je ne peux pas faire en production.
Existe-t-il un moyen plus efficace de procéder?
Si vous souhaitez tester l'ensemble de données, il est téléchargeable ici . Le fichier fait environ 60 Mo, il s'étend à environ 250 Mo. Alternativement, il y a 12 000 lignes dans un résumé GitHub ici .
w.weight
- est-ce vrai? Je cherche à compter les messages avec un poids total (somme des poids de leurs lignes de raison associées) de ltew.weight
.