7
votes

SQL pour les périodes de temps

J'ai une table statistique pour la radio Internet (mySQL), il existe de telles colonnes:

  • IP_ADDRESS
  • time_start (DateTime de départ d'écoute)
  • Time_end (DateTime de la finition d'écoute)

    J'ai besoin de sélectionner le pic d'auditeurs pour chaque jour, je veux dire nombre maximum d'auditeurs IP uniques simultanées.

    et il serait également génial d'avoir du temps de début et de fin de ce pic .

    Par exemple: xxx

     Entrez la description de l'image ici


1 commentaires

Pourriez-vous s'il vous plaît poster un exemple de script de génération de données que vous utilisez


4 Réponses :


0
votes
SELECT
  COUNT(*)               AS listeners,
  current.time_start,    AS peak_start,
  MIN(overlap.time_end)  AS peak_end
FROM
  yourTable    AS current
INNER JOIN
  yourTable    AS overlap
    ON  overlap.time_start <= current.time_start
    AND overlap.time_end   >  current.time_start
GROUP BY
  current.time_start,
  current.time_end
HAVING
  MIN(overlap.time_end) < COALESCE((SELECT MIN(time_start) FROM yourTable WHERE timeStart > current.timeStart), current.time_end+1)
For each record, join on everything that overlaps.The MIN() of the overlapping records' time_end is when the first current listener stops listening.If that time is less than next occurance of a time_start, it's a peak.  (Peak = start immediately followed by a stop)

10 commentaires

Merci, essayé votre requête via phpmyadmin ... MySQL s'est arrêté pendant environ 10 minutes (il n'y a que 35 000 lignes dans la table) et aucun résultat n'a été renvoyé.


Peut-être que nous devons limiter les dates ou utiliser le regroupement de jour?


@ARTICOBANDURURININI - Y a-t-il des champs supplémentaires à rejoindre, et / ou est le time_end toujours le même jour que le time_start ?


Aucun champ supplémentaire à rejoindre et time_end peut être le lendemain, par exemple. L'auditeur pourrait commencer à écouter la radio à 23h30 et à finir à 00h25 le lendemain


@ARTICOBANDURININI - Version légèrement différente ajoutée, pas sûr que ce sera beaucoup plus rapide. Y a-t-il une durée maximale pour tout auditeur?


La durée n'est pas limitée, certaines sessions d'écoute peuvent être plus longues qu'un jour ou même plus


@Articobandurinini - Les changements ont-ils aidé?


MySQL a dit: # 1054 - Colonne inconnue 'Current.Time_end' dans "Avoir la clause"


Le même ... 10 minutes de rotation et 100% CPU pour MySQLD - et le résultat est "Le serveur fermé la connexion sans envoyer de données".


Peut-être que ce serait plus facile si je change la structure de données après la suggestion de Max?



3
votes

IMHO Il est plus simple de charger ces 35 000 rangées en mémoire, de les énumérer et de conserver un compte d'auditeur simultané à un moment donné.
Ce serait plus simple si vous chargez la ligne dans le format suivant: xxx

afin de pouvoir charger les données commandées par heure et que vous devriez simplement énumérer toutes les lignes de conserver une liste d'écoute de la propriété intellectuelle.

Quoi qu'il en soit, comment envisagez-vous plusieurs connexions de la même adresse IP?
Il peut y avoir 10 auditeurs différents derrière une NAT en utilisant la même adresse IP.

mise à jour: Vous n'avez pas besoin de changer la structure de base de données, il suffit d'utiliser un SQL différent pour charger les données xxx

à l'aide de ce SQL, vous devriez pouvoir charger toutes les données, puis énumérer toutes les lignes.
Il est important que les lignes soient triées correctement.

Si StartStop = 1 C'est SOMONE qui commence à écouter -> Ajouter C'est IP de la liste des auditeurs et incrémenter les écouteurs comptent par 1
Si StartStop = 0 c'est une personne qui arrête d'écouter -> Supprimer c'est IP de la liste des auditeurs et décrémenter le nombre d'écouteurs par 1

et dans la vérification de la boucle d'énumération lorsque vous atteignez le nombre maximum d'auditeurs simultanés


1 commentaires

Merci max! Au début, sur les multiples connexions. ICECAST est capable de suivre tous les auditeurs séparément, malgré la propriété intellectuelle, il ne s'agira donc que de plusieurs rangées dans la table avec la même adresse IP. Je peux changer la structure de données, mais pourriez-vous vous fournir le SQL pour cette nouvelle structure, car je ne suis pas assez bon dans une telle question ...



2
votes

laisser aller à trouver un algorithme pour obtenir des résultats avec les meilleures performances.

  • Temps d'épissage Strong>: Le temps est une dimension continue, nous avons besoin de quelques points pour marquer en tant que point de contrôle où un recomptage d'auditeur. Comment trouver des intervalles ou une vérification de l'auditeur de radio total. Je pense que la meilleure stratégie est d'obtenir différents time_start code> et time_end code>. Li> ul>

    C'est mon approche du temps divisé. Je crée une vue pour simplifier la poste: p> xxx pré>

    Je vous suggère 2 index de base de données: p> xxx pré>

    pour éviter les tablescan. p>

    • Comptez les auditeurs Peak Strort>: Rejoignez la table précédente avec votre table pour effectuer un raccomptage de pic à chaque point de contrôle: LI> ul>

      Ceci est mon approche pour les auditeurs de comptage par heure de contrôle: p> xxx pré>

      N'oubliez pas de créer un index de base de données sur votre_table (time_start, time_end)

      • à la recherche de maximum pic fort>: malheureusement mysql ne possède pas de fonctions analytiques, alors sur la partition code> n'est pas disponible et n'est pas un moyen de prendre maximum le pic sur une journée vue précédente. Ensuite, vous devriez obtenir un maximum de points de vue précédents. Il s'agit d'une opération tueur de performance forte>. Je vous suggère de faire cette opération et ensuite sur la logique de l'application et non dans la base de données. li> ul>

        C'est mon approche pour obtenir max_peak par jour ( tueur de performance strong>): p>

        select 
           cast(p_time as date) as p_day, 
           min( p_time ) as slot_from, 
           max( p_time) as slot_to, 
           peak
        from 
           peak_by_time_and_previous p
              inner join 
           max_peak_by_day m
              on cast(p.p_time as date) = m.p_day and
                 p.peak = m.max_peak
        where 
           p.peak = p.previous_peak
        group by  cast(p_time as date) 
        
        • à la recherche de délais de fente strong>: à ce moment, vous avez max_peak code> pour chaque jour, vous devez maintenant rechercher des temps de chèque continus code> avec même max_peak. Aussi mysql ne possède pas de fonctions statistiques ni CTE. Je vous suggère que ce code sera écrit sur la couche d'application. Mais, si vous voulez faire cela dans la solution de base de données, c'est un moyen ( Tauteur de performance d'avertissement Strong>): Li> ul>

          Premier, EXTENDRE PEAK_BY_TIME CODE> Voir le pic précédent pour P_Time et pour P_Time précédent: P>

          create view time_split_extended as
          select c.p_time, max( p.p_time) as previous_ptime
          from 
            time_split c
              inner join 
            time_split p
              on p.p_time < c.p_time
          group by c.p_time
          
          create view peak_by_time_and_previous as
          select 
             te.p_time,  
             te.previous_ptime, 
             pc.peak as peak, 
             pp.peak as previous_peak
          from 
            time_split_extended te
              inner join 
            peak_by_time pc on te.p_time = pc.p_time
              inner join
            peak_by_time pp on te.previous_ptime = pp.p_time
          


0 commentaires

1
votes

Ceci est essentiellement une implémentation de la réponse donnée par max ci-dessus. Pour la simplicité, je représenterai chaque épisode d'écoute comme une heure de départ et une longueur en tant que valeurs entières (elles pourraient être modifiées vers des quertimes réelles, puis les requêtes devraient être modifiées pour utiliser la date d'arithmétique.)

SET @idx=0;
SET @n=0;
SELECT (@idx := @idx + 1) as idx,
       t,
       (@n := @n + delta) as n
  FROM
  (SELECT start AS t,
          1 AS delta
     FROM episodes
     UNION ALL
     SELECT start + len AS t,
            -1 AS delta FROM episodes
     ORDER BY t) stage

+------+--------+------+
| idx  | t      | n    |
+------+--------+------+
|    1 |      8 |    1 |
|    2 |    106 |    2 |
|    3 |    203 |    3 |
|    4 |    274 |    2 |
|    5 |    533 |    3 |
|    6 |    586 |    2 |
...


0 commentaires