2010-09-20 9 views
2

J'ai une table où une ou plusieurs entrées avec la même valeur 'id' peuvent être insérées dans notre journal/table de faits (contient plus de 100 millions d'enregistrements)
A une fréquence donnée, un nouvel enregistrement est inséré dans cette table avec une nouvelle valeur pour les colonnes 'created' et 'view_percent' (pourcentage d'une vidéo vue).
Avec deux requêtes différentes, je voudrais revenir:
Requête MySQL - Utilisation d'Agrégat et Grouper pour générer des résultats séparés

Résultat souhaité 1:

 
+------------------+--------------+-------------+------------------+------------+ 
| archive_asset_id | asset_title | count_asset | avg_view   | time_day | 
+------------------+--------------+-------------+------------------+------------+ 
|   83386 | Oliver James |   4 | 36.75   | 2010-08-09 | 
+------------------+--------------+-------------+------------------+------------+ 

Avec cette requête, je ne suis pas en mesure de filtrer les dossiers nécessaires lors de l'exécution au total fonction ... au lieu de la moyenne de toutes les lignes prises avec une valeur résultant de 31,307

SELECT archive_asset_id, asset_title, COUNT(DISTINCT id * 1000000 + archive_asset_id) AS count_asset, AVG(view_percent) AS avg_view, FROM_UNIXTIME(created, '%Y-%m-%d') AS time_day 
FROM log_embed_video 
WHERE archive_asset_id = 83386 
AND created >= 1281312000 
AND created < 1281484800 
GROUP BY time_day 
ORDER BY time_day; 

Résultat souhaité 2:

 
+------------+------------------+---------------+------------------+-------------------------------+ 
| time_day | archive_asset_id | asset_title | MAX(view_percent) | occurrences MAX(view_percent) | 
+------------+------------------+---------------+------------------+-------------------------------+ 
| 2010-08-09 |   83386 | Oliver James |    13 | 1        | 
| 2010-08-09 |   83386 | Oliver James |    17 | 2        | 
| 2010-08-09 |   83386 | Oliver James |    100 | 1        | 
+------------+------------------+---------------+-------------------+------------------------------+ 

Ceci est la requête que je l'ai utilisé pour résultat 2, mais pas tout à fait ce que je veux ... le groupe par des rendements de 4 log_embed_video.id résultats ... qui est à prévoir pour la requête donnée, mais pas la sortie désirée.

SELECT id, FROM_UNIXTIME(created, '%Y-%m-%d') AS time_day, archive_asset_id, asset_title, COUNT(DISTINCT id * 1000000 + archive_asset_id) AS 'count_asset', MAX(view_percent) as 'max_view_percent' 
FROM log_embed_video 
WHERE archive_asset_id = 83386 
AND created >= 1281312000 
AND created < 1281484800 
GROUP BY time_day, id 



données conditionné:
Les lignes marquent avec KEEP est les données que je veux travailler avec quand le résultat retour 1 et le résultat 2.

SELECT id, archive_asset_id, asset_title, view_percent, FROM_UNIXTIME(created, '%Y-%m-%d') AS time_day 
FROM log_embed_video 
WHERE archive_asset_id = 83386 
AND created >= 1281312000 
AND created < 1281484800 
ORDER BY id, view_percent; 
 
+----------+------------------+--------------+--------------+------------+ 
| id  | archive_asset_id | asset_title | view_percent | time_day | 
+----------+------------------+--------------+--------------+------------+ 
| 43326898 |   83386 | Oliver James |   0 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43326898 |   83386 | Oliver James |   13 | 2010-08-09 | + KEEP 
| 43432090 |   83386 | Oliver James |   0 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43432090 |   83386 | Oliver James |   17 | 2010-08-09 | + KEEP 
| 43432092 |   83386 | Oliver James |   0 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43432092 |   83386 | Oliver James |   17 | 2010-08-09 | + KEEP 
| 43470093 |   83386 | Oliver James |   0 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   17 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   35 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   52 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   69 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   87 | 2010-08-09 | - DISCARD RECORD/DUPLICATE 
| 43470093 |   83386 | Oliver James |   100 | 2010-08-09 | + KEEP 
+----------+------------------+--------------+--------------+------------+ 



Table et des données brutes:

CREATE TABLE `log_embed_video` (
    `id` int(11) NOT NULL, 
    `archive_asset_id` int(11) NOT NULL, 
    `asset_title` varchar(255) NOT NULL, 
    `view_percent` float NOT NULL, 
    `created` int(11) NOT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


INSERT INTO `log_embed_video` VALUES 
(43326898, 83386, 'Oliver James', 0, 1281327306), 
(43326898, 83386, 'Oliver James', 13, 1281327327), 
(43432090, 83386, 'Oliver James', 0, 1281371423), 
(43432090, 83386, 'Oliver James', 17, 1281371445), 
(43432092, 83386, 'Oliver James', 0, 1281371424), 
(43432092, 83386, 'Oliver James', 17, 1281371446), 
(43470093, 83386, 'Oliver James', 0, 1281380789), 
(43470093, 83386, 'Oliver James', 17, 1281380810), 
(43470093, 83386, 'Oliver James', 35, 1281380830), 
(43470093, 83386, 'Oliver James', 52, 1281380850), 
(43470093, 83386, 'Oliver James', 69, 1281380871), 
(43470093, 83386, 'Oliver James', 87, 1281380891), 
(43470093, 83386, 'Oliver James', 100, 1281380906); 
+0

Je ne trouve pas de question ici - je ne sais vraiment pas ce que vous demandez. – RedFilter

+0

+1 pour les données de l'échantillon et créer une table ... Cependant, il n'est toujours pas clair (pour moi) ce que vous voulez atteindre (essayez d'expliquer les «résultats souhaités» aussi en mots, juste regarder les données ne m'aide pas comprenez ce que vous essayez d'atteindre) – Unreason

+0

Comment le code devrait-il passer au jour suivant (ex: 23:59 => 50%/00:01 => 55%)? – Wrikken

Répondre

0

Vérifiez si vous risquez de rendre plus clair pour vous

SELECT archive_asset_id, AVG(actual_percent) 
FROM (SELECT id, archive_asset_id, asset_title, 
      MAX(view_percent) as actual_percent 
     FROM log_embed_video GROUP by id) T 
GROUP BY archive_asset_id; 

Il retourne:

+------------------+---------------------+ 
| archive_asset_id | AVG(actual_percent) | 
+------------------+---------------------+ 
|   83386 |    36.75 | 
+------------------+---------------------+ 

Quelques notes

  • cela ne fonctionnera pas bien sur les enregistrements 100M
  • également vous pourriez vouloir normaliser vos données pour améliorer les performances (ce qu'il fera dans ce cas; déplacer fondamentalement les lignes finales réelles dans leur propre table me fait beaucoup plus de sens)
  • l'expression COUNT(DISTINCT id * 1000000 + archive_asset_id) a attiré mon attention comme quelque chose de bizarre; êtes-vous sûr de ne pas vouloir dire simplement COUNT(*) ou COUNT(id)?

EDIT:

Pour la deuxième

SELECT archive_asset_id, actual_percent, count(*) 
FROM (SELECT id, archive_asset_id, asset_title,    
      MAX(view_percent) as actual_percent   
     FROM log_embed_video GROUP by id) T 
GROUP BY archive_asset_id, actual_percent; 

+------------------+----------------+----------+ 
| archive_asset_id | actual_percent | count(*) | 
+------------------+----------------+----------+ 
|   83386 |    13 |  1 | 
|   83386 |    17 |  2 | 
|   83386 |   100 |  1 | 
+------------------+----------------+----------+ 
+0

'COUNT (identificateur DISTINCT * 1000000 + archive_asset_id)' Je suppose que c'est un argument pour obtenir 'COUNT (ID DISTINCT, archive_asset_id)' – Wrikken

+0

Nous utilisons une base de données Infobright Brighthouse conçue pour interroger de grands ensembles de données. Actuellement, cette base de données ne prend pas en charge COUNT (DISTINCT col1, col2), c'est donc leur travail recommandé autour de – Scott

+0

@ Unreason - ces deux requêtes modifiées fonctionnent très bien. Lors du filtrage des données par plage de dates et par un ID d'actif unique, les résultats sont renvoyés en moins de 200 ms avec plus de 100 millions d'enregistrements dans ce tableau. Merci d'avoir pris le temps de répondre à ma question! – Scott

1

Tous max pourcentage lignes par-id pour un identifiant unique:

SELECT a.* 
FROM log_embed_video a 
LEFT JOIN log_embed_video b 
ON b.id = a.id 
AND b.view_percent > a.view_percent 
WHERE b.id IS NULL 
-- possibly limit on date for more performance. 

Performance sage ce qui est mieux:

SELECT * FROM (
    SELECT id, archive_asset_id, asset_title, view_percent, created, 
     @rn := IF(id != @old_id,1,@rn + 1) as rownumber, 
     @old_id := id 
    FROM log_embed_video 
    JOIN (SELECT @rn:=0,@old_id:=0) void 
    ORDER BY id, view_percent DESC 
) a WHERE rownumber=1; 
+0

+1 parce que cela fonctionne :) Je me demande quelle solution Scott sera plus facile à comprendre ... – Unreason

+0

La lisibilité souffre si n'est pas familier avec le tour LEFT JOIN en effet. Il souffre aussi un peu de performance. Je peux entrer une réponse encore plus illisible qui est beaucoup plus rapide ... – Wrikken

+0

Là, maintenant toute la lisibilité est hors de la fenêtre en faveur de la performance: P – Wrikken