2011-11-22 1 views
2

j'ai le code suivantDéplacement de la requête mysql de la boucle

function cron_day_counts() 
{ 
    $subids = get_subids(); 
    array_push($subids, ''); 
    $from = '2011-10-19'; 
    $to = '2011-10-20'; 
    $days = days_interval($from, $to); 
    $result_array = array(); 
    foreach ($subids as $subid) 
    { 
     for ($i = 0; $i < $days; $i++) 
     { 
      $date = date('Y-m-d', strtotime($from . '+ ' . $i . ' day')); 
      $date_prev = date('Y-m-d', strtotime($date . '- 1 day')); 

      $unique_id_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ids`'); 
      $unique_id_result = mysql_fetch_assoc($unique_id_query); 

      $total_id_query = mysql_query('SELECT COUNT(DISTINCT `id`,`subid`) AS `total_ids` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '')); 
      $total_id_result = mysql_fetch_assoc($total_id_query); 

      $unique_ip_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ips`'); 
      $unique_ip_result = mysql_fetch_assoc($unique_ip_query); 

      $total_ip_query = mysql_query('SELECT COUNT(DISTINCT `ip`,`subid`) AS `total_ips` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '')); 
      $total_ip_result = mysql_fetch_assoc($total_ip_query); 

      $global_query = mysql_query('SELECT COUNT(`id`) AS `global` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '')); 
      $global_result = mysql_fetch_assoc($global_query); 

      $result = array(); 
      $result['subid'] = $subid; 
      $result['date'] = $date; 
      $result['unique_ids'] = $unique_id_result['unique_ids']; 
      $result['total_ids'] = $total_id_result['total_ids']; 
      $result['unique_ips'] = $unique_ip_result['unique_ips']; 
      $result['total_ips'] = $total_ip_result['total_ips']; 
      $result['global'] = $global_result['global']; 

      $result_array[] = $result; 
     } 

    } 
    //db insert 
    return $result_array; 
} 

Je veux déplacer toute la requête de la foreach et pour les boucles, je crois que cela fonctionnerait plus vite. Je suis coincé o, n'ayant aucune idée de comment faire cela. Toute aide serait appréciée.

Répondre

0

Je dirais à tout le moins, vous devez combiner les requêtes en la boucle à seulement un pour chaque jour. Donc, pour une période de 5 jours, vous auriez 5 questions.

Vous pouvez également avoir une seule requête pour toute la plage de dates et la déplacer en dehors de la boucle (comme décrit par ajreal). Ensuite, utilisez PHP pour trier tout cela.

Pour les grandes bases de données, je préférerais fractionner un peu les requêtes pour équilibrer la charge et le risque de dépassement de délai. Aide également à maintenir le code maintenable.

Vous devriez également regarder comment votre base de données est structurée et indexée.

Est-ce que c'est lent?

et la fonction array_push est-elle nécessaire? (Ce n'est pas que cela permettrait d'économiser beaucoup, je me demandais juste parce qu'il semble redondant)

Si c'est vraiment lent alors peut-être penser à la restructuration du processus complètement en fonction de la façon dont vous l'utilisez.

Vous pouvez, par exemple, à 00h01 chaque jour faire quelque chose comme ceci:

  • requête les jours log et compter le IP unique/total/ID s'élève
  • suffit d'insérer les numéros de compte et date à une table séparée
  • archive les jours Connectez-vous à une table d'archive séparée ou même un db séparé comme mongoDB

de cette façon, vous pouvez effectuer querys simples pour afficher la données et manipuler les nombres à votre contenu de coeur avec de bonnes performances. Et par l'archivage, vous gardez la table de requête petite en supprimant les lignes inutiles mais en conservant un journal si nécessaire plus tard.

Bien sûr, cela peut ne pas correspondre à la configuration de votre db.

+0

Cette fonction n'est pas terminée, je fais cette requête exactement pour insérer des valeurs pour séparer la table. Il sera exécuté chaque jour via cron. – mintobit

+0

a du sens, pourrait voir à la fin retourne à un db mais ne savait pas quoi faire. – Taylor

+0

si cela est exécuté quotidiennement pourquoi avez-vous besoin d'une boucle basée sur des jours? vous pouvez sûrement faire disparaître une grande partie de ce code et juste interroger une fois? – Taylor

-1

Prenez tous vos subids, et faites une extraction avec un prédicat IN pour obtenir toutes les valeurs à la fois. Remplissez cela dans un tableau, puis bouclez le tableau. Utilisez l'extension PDO :: MySQL à la place des extensions MySQL ou MySQLi.

+0

Merci pour la réponse rapide. Le problème est que j'ai aussi la colonne 'date' dans la clause WHERE, et cela dépend de la boucle FOR. – mintobit

+0

Vous devrez toujours boucler les dates, car celles-ci sont des valeurs "changeantes", à moins que vous ne souhaitiez créer un tableau de celles-ci et les inclure dans une autre partie "IN". –

+0

J'ai environ 400.000 d'enregistrements, je suppose que cela améliorera la performance de manière significative, ai-je raison (je veux dire déplacer les requêtes hors des boucles). J'ai aussi une autre idée, combiner toutes les requêtes en une, en espérant obtenir encore plus de performance. Dites-moi où je me trompe. – mintobit

-1

De cette façon, vous pouvez préparer les requêtes qui vont accélérer considérablement le temps d'exécution des appels mysql.

0

obtenir tous les subid

pour chaque table,
construire une seule requête pour filtrer entre la date la plus petite et la plus grande date
et le groupe à la date

select subid, `date`, count(*) ... 
where subid IN($subids) and `date` between $smallest and $largest 
group by subid, `date` 

itérer le résultat , et stocké le résultat dans le tableau, avec subid, date comme clé

$mysql_results = array[$subid][$date] ... 

enfin, itérer les SubIDs de $ et la date, comme

foreach ($subids as $subid) 
{ 
    for ($i = 0; $i < $days; $i++) 
    { 
    // set $date 

    // check $mysql_results[$subid][$date] exists 
    } 
} 

avec quelque chose comme ci-dessus, vous ne devez 5 requêtes au lieu de

5 x total days x size of the subids 
+0

Sons parfaits !!! Je vais essayer d'ajuster votre pattern à cette requête: "SELECT (SELECT COUNT (DISTINCT' id', 'subid') DE' tb_stats' WHERE 'date' <= date ET 'subid' = $ subid) - (SELECT COUNT (DISTINCT 'id',' subid') FROM 'tb_stats' WHERE' date' <= $ date_prev ET 'subid' = $ subid) AS' unique_ids' " – mintobit

+0

Hmmm, je suis encore coincé. J'ai besoin de compter (select count (id distinct, subid) d'où tb_stats où subid dans (...) et date entre ... et ...) - (select count (distinct id, subid) d'où tb_stats où subid dans (...) et date entre ... et ...) Mais cela ne marchera pas, parce que j'ai besoin de calculer la quantité de ID distincte, subid où subid = ... et date = ... MOINS le quantité d'ID distinct, subid où subid = ... et date = LE JOUR AVANT – mintobit

Questions connexes