diff --git a/lib/statslib.php b/lib/statslib.php
index 6be5da6..e2200ab 100644
--- a/lib/statslib.php
+++ b/lib/statslib.php
@@ -91,6 +91,7 @@ function stats_cron_daily($maxdays=1) {
 
     // Note: This will work fine for sites running cron each 4 hours or less (hoppefully, 99.99% of sites). MDL-16709
     // check to make sure we're due to run, at least 20 hours after last run
+
     if (isset($CFG->statslastexecution) and ((time() - 20*60*60) < $CFG->statslastexecution)) {
         mtrace("...preventing stats to run, last execution was less than 20 hours ago.");
         return false;
@@ -127,16 +128,29 @@ function stats_cron_daily($maxdays=1) {
     $guest     = get_guest();
     $guestrole = get_guest_role();
 
-    list($enroljoin, $enrolwhere)       = stats_get_enrolled_sql($CFG->statscatdepth, true);
-    list($enroljoin_na, $enrolwhere_na) = stats_get_enrolled_sql($CFG->statscatdepth, false);
-    list($fpjoin, $fpwhere)             = stats_get_enrolled_sql(0, true);
-
     mtrace("Running daily statistics gathering, starting at $timestart:");
 
+    mtrace("...creating stats enrollment tables: ", false);
+    if ( ! stats_create_enrollments_view($CFG->statscatdepth, false) ) {
+        mtrace("ERROR");
+        return false;
+    }
+    if ( ! stats_create_enrollments_view($CFG->statscatdepth, true) ) {
+        mtrace("ERROR");
+        return false;
+    }
+    if ( ! stats_create_enrollments_view(0, true, false) ) {
+        mtrace("ERROR");
+        return false;
+    }
+    mtrace("OK");
+
+
     $days = 0;
     $failed = false; // failed stats flag
 
     while ($now > $nextmidnight) {
+
         if ($days >= $maxdays) {
             mtrace("...stopping early, reached maximum number of $maxdays days - will continue next time.");
             set_cron_lock('statsrunning', null);
@@ -154,31 +168,33 @@ function stats_cron_daily($maxdays=1) {
         $daystart = time();
 
         $timesql  = "l.time >= $timestart  AND l.time  < $nextmidnight";
-        $timesql1 = "l1.time >= $timestart AND l1.time < $nextmidnight";
-        $timesql2 = "l2.time >= $timestart AND l2.time < $nextmidnight";
 
-        stats_daily_progress('init');
+        mtrace("...creating logs temporary table: ", false);
+        if ( ! stats_create_logs_view($timesql) ) {
+            mtrace("ERROR");
+            return false;
+        } 
+        mtrace("OK");
 
+        stats_daily_progress('init');
 
-    /// find out if any logs available for this day
+        /// find out if any logs available for this day
         $sql = "SELECT 'x'
-                  FROM {$CFG->prefix}log l
-                 WHERE $timesql";
+                FROM {$CFG->prefix}tmp_stats_log l";
         $logspresent = get_records_sql($sql, 0, 1);
 
-    /// process login info first
-        $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads)
-
-                SELECT 'logins', timeend, courseid, userid, count(statsreads)
-                  FROM (
-                           SELECT $nextmidnight AS timeend, ".SITEID." AS courseid, l.userid, l.id AS statsreads
-                             FROM {$CFG->prefix}log l
-                            WHERE action = 'login' AND $timesql
-                       ) inline_view
-              GROUP BY timeend, courseid, userid
-                HAVING count(statsreads) > 0";
+        /// process login info first
 
+        $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads)
+        SELECT 'logins',  " . $nextmidnight . " AS timeend, " . SITEID . " AS courseid, l.userid, count(l.id)
+                FROM {$CFG->prefix}tmp_stats_log l
+                WHERE l.action = 'login' AND " . " 
+                      l.course = " . SITEID . "
+                GROUP BY l.userid
+                HAVING count(l.id) > 0";
+ 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 1");
             $failed = true;
             break;
         }
@@ -196,12 +212,12 @@ function stats_cron_daily($maxdays=1) {
                 sql_null_from_clause();
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 2");
             $failed = true;
             break;
         }
         stats_daily_progress('2');
 
-
         // Enrolments and active enrolled users
         //
         // Unfortunately, we do not know how many users were registered
@@ -217,45 +233,47 @@ function stats_cron_daily($maxdays=1) {
 
         $sql = "INSERT INTO {$CFG->prefix}stats_daily (stattype, timeend, courseid, roleid, stat1, stat2)
 
-                SELECT 'enrolments', timeend, courseid, roleid, COUNT(DISTINCT userid), 0
-                  FROM (
-                           SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, pl.userid
-                             FROM (
-                                      SELECT DISTINCT ra.roleid, ra.userid, c.id as courseid
-                                        FROM {$CFG->prefix}role_assignments ra $enroljoin_na
-                                       WHERE $enrolwhere_na
-                                   ) pl
-                       ) inline_view
-              GROUP BY timeend, courseid, roleid";
+                SELECT 'enrolments', $nextmidnight AS timeend, courseid, roleid, COUNT(DISTINCT userid), 0
+                FROM {$CFG->prefix}tmp_stats_enrollments_na
+                GROUP BY courseid, roleid";
 
         if (!execute_sql($sql, false)) {
+            mtrace("failed query 3");
             $failed = true;
             break;
         }
         stats_daily_progress('3');
 
         // using table alias in UPDATE does not work in pg < 8.2
-        $sql = "UPDATE {$CFG->prefix}stats_daily
-                   SET stat2 = (SELECT COUNT(DISTINCT ra.userid)
-                                  FROM {$CFG->prefix}role_assignments ra $enroljoin_na
-                                 WHERE ra.roleid = {$CFG->prefix}stats_daily.roleid AND
-                                       c.id = {$CFG->prefix}stats_daily.courseid AND
-                                       $enrolwhere_na AND
-                                       EXISTS (SELECT 'x'
-                                                 FROM {$CFG->prefix}log l
-                                                WHERE l.course = {$CFG->prefix}stats_daily.courseid AND
-                                                      l.userid = ra.userid AND $timesql))
-                 WHERE {$CFG->prefix}stats_daily.stattype = 'enrolments' AND
+
+        $sql = "SELECT id, courseid, roleid
+                FROM {$CFG->prefix}stats_daily
+                WHERE {$CFG->prefix}stats_daily.stattype = 'enrolments' AND
                        {$CFG->prefix}stats_daily.timeend = $nextmidnight AND
                        {$CFG->prefix}stats_daily.courseid IN
                           (SELECT DISTINCT l.course
-                             FROM {$CFG->prefix}log l
-                            WHERE $timesql)";
+                             FROM {$CFG->prefix}tmp_stats_log l)";
+
+        $res = get_records_sql($sql);
+        foreach ( $res as $r ) {
+
+            $sql = "UPDATE {$CFG->prefix}stats_daily
+                        SET stat2 = (SELECT COUNT(DISTINCT te.userid)
+                                FROM {$CFG->prefix}tmp_stats_enrollments_na te, {$CFG->prefix}tmp_stats_log l
+                                WHERE l.userid = te.userid AND
+                                      l.course = {$r->courseid} AND
+                                      te.roleid = {$r->roleid} AND
+                                      te.courseid = {$r->courseid})
+                        WHERE id={$r->id}";
+ 
+            if ($logspresent and !execute_sql($sql, false)) {
+                mtrace("failed query 4");
+                $failed = true;
+                break;
+            }
 
-        if ($logspresent and !execute_sql($sql, false)) {
-            $failed = true;
-            break;
         }
+
         stats_daily_progress('4');
 
     /// now get course total enrolments (roleid==0) - except frontpage
@@ -263,39 +281,46 @@ function stats_cron_daily($maxdays=1) {
 
                 SELECT 'enrolments', timeend, id, nroleid, COUNT(DISTINCT userid), 0
                   FROM (
-                           SELECT $nextmidnight AS timeend, c.id, 0 AS nroleid, ra.userid
-                             FROM {$CFG->prefix}role_assignments ra $enroljoin_na
-                            WHERE c.id <> ".SITEID." AND $enrolwhere_na
+                           SELECT $nextmidnight AS timeend, te.courseid AS id, 0 AS nroleid, te.userid
+                           FROM {$CFG->prefix}tmp_stats_enrollments_na te
+                           WHERE te.courseid <> ".SITEID."
                        ) inline_view
               GROUP BY timeend, id, nroleid
               HAVING COUNT(DISTINCT userid) > 0";
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 5");
             $failed = true;
             break;
         }
         stats_daily_progress('5');
 
-        $sql = "UPDATE {$CFG->prefix}stats_daily
-                   SET stat2 = (SELECT COUNT(DISTINCT ra.userid)
-                                  FROM {$CFG->prefix}role_assignments ra $enroljoin_na
-                                 WHERE c.id = {$CFG->prefix}stats_daily.courseid AND
-                                       $enrolwhere_na AND
-                                       EXISTS (SELECT 'x'
-                                                 FROM {$CFG->prefix}log l
-                                                WHERE l.course = {$CFG->prefix}stats_daily.courseid AND
-                                                      l.userid = ra.userid AND $timesql))
-                 WHERE {$CFG->prefix}stats_daily.stattype = 'enrolments' AND
-                       {$CFG->prefix}stats_daily.timeend = $nextmidnight AND
-                       {$CFG->prefix}stats_daily.roleid = 0 AND
-                       {$CFG->prefix}stats_daily.courseid IN
-                          (SELECT l.course
-                             FROM {$CFG->prefix}log l
-                            WHERE $timesql AND l.course <> ".SITEID.")";
+        $sql = "SELECT * FROM {$CFG->prefix}stats_daily
+                WHERE stattype = 'enrolments' AND
+                      timeend = $nextmidnight AND
+                      roleid = 0 AND
+                      courseid IN
+                          (SELECT DISTINCT l.course
+                             FROM {$CFG->prefix}tmp_stats_log l
+                            WHERE l.course <> ".SITEID.")";
+
+        $res = get_records_sql($sql);
+        foreach ( $res as $r ) {
+            $sql = "UPDATE {$CFG->prefix}stats_daily
+                        SET stat2 = (SELECT COUNT(DISTINCT te.userid)
+                                  FROM {$CFG->prefix}tmp_stats_enrollments_na te,
+                                       {$CFG->prefix}tmp_stats_log l 
+                                 WHERE te.courseid = {$r->courseid} AND
+                                       l.course = te.courseid AND
+                                       l.userid = te.userid
+                                )
+                        WHERE id = {$r->id}";
 
-        if ($logspresent and !execute_sql($sql, false)) {
-            $failed = true;
-            break;
+            if ($logspresent and !execute_sql($sql, false)) {
+                mtrace("failed query 6");
+                $failed = true;
+                break;
+            }
         }
         stats_daily_progress('6');
 
@@ -308,11 +333,12 @@ function stats_cron_daily($maxdays=1) {
                          WHERE u.deleted = 0) AS stat1,
                        (SELECT COUNT(DISTINCT u.id)
                           FROM {$CFG->prefix}user u
-                               JOIN {$CFG->prefix}log l ON l.userid = u.id
-                         WHERE u.deleted = 0 AND $timesql) AS stat2" .
+                               JOIN {$CFG->prefix}tmp_stats_log l ON l.userid = u.id
+                         WHERE u.deleted = 0) AS stat2" .
                 sql_null_from_clause();
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 7");
             $failed = true;
             break;
         }
@@ -332,6 +358,7 @@ function stats_cron_daily($maxdays=1) {
                      WHERE stattype = 'enrolments' AND courseid = ".SITEID." AND
                            roleid = $defaultfproleid AND timeend = $nextmidnight";
             if ($logspresent and !execute_sql($sql, false)) {
+                mtrace("failed query 8"); 
                 $failed = true;
                 break;
             }
@@ -346,10 +373,11 @@ function stats_cron_daily($maxdays=1) {
                            (SELECT COUNT(DISTINCT u.id)
                               FROM {$CFG->prefix}user u
                                    JOIN {$CFG->prefix}log l ON l.userid = u.id
-                             WHERE u.deleted = 0 AND $timesql) AS stat2" .
+                             WHERE u.deleted = 0) AS stat2" .
                     sql_null_from_clause();
 
             if ($logspresent and !execute_sql($sql, false)) {
+                mtrace("failed query 9");
                 $failed = true;
                 break;
             }
@@ -360,77 +388,132 @@ function stats_cron_daily($maxdays=1) {
             stats_daily_progress('x');
         }
 
+        /// individual user stats (including not-logged-in) in each course, this is slow - reuse this data if possible
+        /// We are doing this in 6 steps:
+        ///
+        ///         1. Calculate just statsreads putting 0 in statswrites
+        ///         2. Update statsreads rows with its corresponding statswrites
+        ///         3. Calculate statswrites not inserted yet. They will have statsreads = 0
+        ///         4. Calculate userid = 0 and courseid = 1 statsreads and writes
+        ///         5. Insert a stats=0 and statswrites = 0 to users that are in tmp_stats_logs but are not
+        ///            yet in stats_user_daily
+        
+        $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads, statswrites)
+                SELECT 'activity' AS stattype, $nextmidnight as timeend, l.course AS courseid, l.userid, COUNT('x') AS statsreads, 0
+                FROM {$CFG->prefix}tmp_stats_log l, {$CFG->prefix}user u
+                WHERE l.userid = u.id AND
+                      l.action IN ('view','view all','history','report','display','view discussion','search','forum','forums','subscribers','view entry','view responses','pre-view','download','view form','view graph','view report')
+                GROUP BY l.userid, l.course";
+
+        if ($logspresent and !execute_sql($sql, false)) {
+            $failed = true;
+            break;
+        }
+
+
+        $sql = "UPDATE {$CFG->prefix}stats_user_daily
+                SET statswrites = (
+                    SELECT COUNT('x')
+                    FROM {$CFG->prefix}tmp_stats_log l
+                    WHERE l.userid = {$CFG->prefix}stats_user_daily.userid AND
+                          l.course = {$CFG->prefix}stats_user_daily.courseid AND
+                          l.action IN ('add','delete','edit','add mod','delete mod','edit sectionenrol','loginas','new','unenrol','update','update mod','upload','talk','choose','choose again','assess','grade','open','set up','submit','add discussion','add post','delete discussion','delete post','move discussion','prune post','update post','add category','add comment','add entry','approve entry','delete category','delete comment','delete entry','edit category','update comment','update entry','attempt','review','update feedback','end','start','update grade attempt','editquestions','hack','agree','comment','newattachment','removeattachments','resubmit','record delete'))
+                WHERE timeend=$nextmidnight AND 
+                      stattype='activity'";
+
+        if ($logspresent and !execute_sql($sql, false)) {
+            $failed = true;
+            break;
+        }
 
 
-    /// individual user stats (including not-logged-in) in each course, this is slow - reuse this data if possible
         $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads, statswrites)
+                SELECT 'activity' AS stattype, $nextmidnight as timeend, l.course courseid, l.userid, 0, COUNT('x') AS statswrites
+                FROM {$CFG->prefix}tmp_stats_log l, {$CFG->prefix}user u
+                WHERE l.userid = u.id AND
+                      l.action IN ('add','delete','edit','add mod','delete mod','edit sectionenrol','loginas','new','unenrol','update','update mod','upload','talk','choose','choose again','assess','grade','open','set up','submit','add discussion','add post','delete discussion','delete post','move discussion','prune post','update post','add category','add comment','add entry','approve entry','delete category','delete comment','delete entry','edit category','update comment','update entry','attempt','review','update feedback','end','start','update grade attempt','editquestions','hack','agree','comment','newattachment','removeattachments','resubmit','record delete') AND
+                NOT EXISTS ( SELECT 1
+                   FROM {$CFG->prefix}stats_user_daily sd
+                   WHERE sd.userid = l.userid AND
+                         sd.stattype = 'activity' AND 
+                         sd.courseid = l.course AND
+                         sd.timeend = $nextmidnight)
+                GROUP BY l.userid, l.course";
+
+        if ($logspresent and !execute_sql($sql, false)) {
+            $failed = true;
+            break;
+        }
 
-                SELECT 'activity' AS stattype, $nextmidnight AS timeend, d.courseid, d.userid,
-                       (SELECT COUNT('x')
-                          FROM {$CFG->prefix}log l
-                         WHERE l.userid = d.userid AND
-                               l.course = d.courseid AND $timesql AND
-                               l.action IN ($viewactions)) AS statsreads,
-                       (SELECT COUNT('x')
-                          FROM {$CFG->prefix}log l
-                         WHERE l.userid = d.userid AND
-                               l.course = d.courseid AND $timesql AND
-                               l.action IN ($postactions)) AS statswrites
-                  FROM (SELECT DISTINCT u.id AS userid, l.course AS courseid
-                          FROM {$CFG->prefix}user u, {$CFG->prefix}log l
-                         WHERE u.id = l.userid AND $timesql
-                       UNION
-                        SELECT 0 AS userid, ".SITEID." AS courseid" . sql_null_from_clause() . ") d";
-                        // can not use group by here because pg can not handle it :-(
+
+        $count_read  = count_records_select('tmp_stats_log', "userid=0 AND course=1 AND action IN ('view','view all','history','report','display','view discussion','search','forum','forums','subscribers','view entry','view responses','pre-view','download','view form','view graph','view report')");
+
+        $count_write = count_records_select('tmp_stats_log', "userid=0 AND course=1 AND action IN ('add','delete','edit','add mod','delete mod','edit sectionenrol','loginas','new','unenrol','update','update mod','upload','talk','choose','choose again','assess','grade','open','set up','submit','add discussion','add post','delete discussion','delete post','move discussion','prune post','update post','add category','add comment','add entry','approve entry','delete category','delete comment','delete entry','edit category','update comment','update entry','attempt','review','update feedback','end','start','update grade attempt','editquestions','hack','agree','comment','newattachment','removeattachments','resubmit','record delete')");
+
+
+        $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads, statswrites)
+                VALUES ( 'activity', $nextmidnight, 1, 0, $count_read, $count_write )";
+
+        if ($logspresent and !execute_sql($sql, false)) {
+            $failed = true;
+            break;
+        }
+
+        $sql = "INSERT INTO {$CFG->prefix}stats_user_daily (stattype, timeend, courseid, userid, statsreads, statswrites)
+                SELECT DISTINCT 'activity' AS stattype, $nextmidnight AS timeend, course AS courseid, userid, 0, 0
+                FROM {$CFG->prefix}tmp_stats_log l
+                WHERE NOT EXISTS ( SELECT 1
+                          FROM {$CFG->prefix}stats_user_daily sud 
+                          WHERE sud.timeend = $nextmidnight AND
+                                sud.stattype = 'activity' AND
+                                sud.userid = l.userid AND
+                                sud.courseid = l.course )";
 
         if ($logspresent and !execute_sql($sql, false)) {
             $failed = true;
             break;
         }
-        stats_daily_progress('10');
 
+        stats_daily_progress('10');
 
     /// how many view/post actions in each course total
         $sql = "INSERT INTO {$CFG->prefix}stats_daily (stattype, timeend, courseid, roleid, stat1, stat2)
 
                 SELECT 'activity' AS stattype, $nextmidnight AS timeend, c.id AS courseid, 0,
                        (SELECT COUNT('x')
-                          FROM {$CFG->prefix}log l1
-                         WHERE l1.course = c.id AND l1.action IN ($viewactions) AND
-                               $timesql1) AS stat1,
+                          FROM {$CFG->prefix}tmp_stats_log l1
+                         WHERE l1.course = c.id AND l1.action IN ($viewactions)
+                               ) AS stat1,
                        (SELECT COUNT('x')
-                          FROM {$CFG->prefix}log l2
-                         WHERE l2.course = c.id AND l2.action IN ($postactions) AND
-                               $timesql2) AS stat2
+                          FROM {$CFG->prefix}tmp_stats_log l2
+                         WHERE l2.course = c.id AND l2.action IN ($postactions)
+                               ) AS stat2
                   FROM {$CFG->prefix}course c
-                 WHERE EXISTS (SELECT 'x'
-                                 FROM {$CFG->prefix}log l
-                                WHERE l.course = c.id and $timesql)";
+                  WHERE  EXISTS (SELECT 'x'
+                                 FROM {$CFG->prefix}tmp_stats_log l
+                                WHERE l.course = c.id )";
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 11");
             $failed = true;
             break;
         }
         stats_daily_progress('11');
 
-
     /// how many view actions for each course+role - excluding guests and frontpage
 
         $sql = "INSERT INTO {$CFG->prefix}stats_daily (stattype, timeend, courseid, roleid, stat1, stat2)
 
                 SELECT 'activity', timeend, courseid, roleid, SUM(statsreads), SUM(statswrites)
                 FROM (
-                         SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
+                         SELECT $nextmidnight AS timeend, te.courseid, te.roleid, sud.statsreads, sud.statswrites
                          FROM {$CFG->prefix}stats_user_daily sud,
-                                  (SELECT DISTINCT ra.userid, ra.roleid, c.id AS courseid
-                                     FROM {$CFG->prefix}role_assignments ra $enroljoin
-                                    WHERE c.id <> ".SITEID." AND
-                                          ra.roleid <> $guestrole->id AND
-                                          ra.userid <> $guest->id AND
-                                          $enrolwhere
-                                  ) pl
-                         WHERE sud.userid = pl.userid AND
-                               sud.courseid = pl.courseid AND
+                              {$CFG->prefix}tmp_stats_enrollments te
+                         WHERE te.courseid <> " . SITEID . " AND
+                               te.roleid <> $guestrole->id AND
+                               te.userid <> $guest->id AND
+                               sud.userid = te.userid AND
+                               sud.courseid = te.courseid AND
                                sud.timeend = $nextmidnight AND
                                sud.stattype='activity'
                      ) inline_view
@@ -438,6 +521,7 @@ function stats_cron_daily($maxdays=1) {
               HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 12");
             $failed = true;
             break;
         }
@@ -456,21 +540,20 @@ function stats_cron_daily($maxdays=1) {
                             WHERE sud.timeend = $nextmidnight AND sud.courseid <> ".SITEID." AND
                                   sud.stattype='activity' AND
                                   (sud.userid = $guest->id OR sud.userid
-                                    NOT IN (SELECT ra.userid
-                                              FROM {$CFG->prefix}role_assignments ra $enroljoin
-                                             WHERE c.id <> ".SITEID." AND  ra.roleid <> $guestrole->id AND
-                                                   $enrolwhere))
+                                    NOT IN (SELECT DISTINCT te.userid
+                                            FROM {$CFG->prefix}tmp_stats_enrollments te
+                                            WHERE te.courseid <> ".SITEID." AND  te.roleid <> $guestrole->id 
+                                           ))
                        ) inline_view
               GROUP BY timeend, courseid, nroleid
                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
-
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 13");
             $failed = true;
             break;
         }
         stats_daily_progress('13');
 
-
     /// how many view actions for each role on frontpage - excluding guests, not-logged-in and default frontpage role
         $sql = "INSERT INTO {$CFG->prefix}stats_daily (stattype, timeend, courseid, roleid, stat1, stat2)
 
@@ -478,13 +561,12 @@ function stats_cron_daily($maxdays=1) {
                   FROM (
                            SELECT $nextmidnight AS timeend, pl.courseid, pl.roleid, sud.statsreads, sud.statswrites
                              FROM {$CFG->prefix}stats_user_daily sud,
-                                      (SELECT DISTINCT ra.userid, ra.roleid, c.id AS courseid
-                                         FROM {$CFG->prefix}role_assignments ra $enroljoin
-                                        WHERE c.id = ".SITEID." AND
-                                              ra.roleid <> $defaultfproleid AND
-                                              ra.roleid <> $guestrole->id AND
-                                              ra.userid <> $guest->id AND
-                                              $enrolwhere
+                                      (SELECT DISTINCT te.userid, te.roleid, te.courseid 
+                                         FROM {$CFG->prefix}tmp_stats_enrollments te 
+                                        WHERE te.courseid = ".SITEID." AND
+                                              te.roleid <> $defaultfproleid AND
+                                              te.roleid <> $guestrole->id AND
+                                              te.userid <> $guest->id 
                                       ) pl
                             WHERE sud.userid = pl.userid AND
                                   sud.courseid = pl.courseid AND
@@ -494,13 +576,14 @@ function stats_cron_daily($maxdays=1) {
               GROUP BY timeend, courseid, roleid
                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 
+
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 14");
             $failed = true;
             break;
         }
         stats_daily_progress('14');
 
-
     /// how many view actions for default frontpage role on frontpage only
         $sql = "INSERT INTO {$CFG->prefix}stats_daily (stattype, timeend, courseid, roleid, stat1, stat2)
 
@@ -511,15 +594,16 @@ function stats_cron_daily($maxdays=1) {
                              WHERE sud.timeend = $nextmidnight AND sud.courseid = ".SITEID." AND
                                    sud.stattype='activity' AND
                                    sud.userid <> $guest->id AND sud.userid <> 0 AND sud.userid
-                                   NOT IN (SELECT ra.userid
-                                             FROM {$CFG->prefix}role_assignments ra $fpjoin
-                                            WHERE c.id = ".SITEID." AND  ra.roleid <> $guestrole->id AND
-                                                  ra.roleid <> $defaultfproleid AND $fpwhere)
+                                   NOT IN (SELECT te.userid
+                                             FROM {$CFG->prefix}tmp_stats_enrollments_wc te
+                                            WHERE te.courseid = ".SITEID." AND  te.roleid <> $guestrole->id AND
+                                                  te.roleid <> $defaultfproleid )
                        ) inline_view
               GROUP BY timeend, courseid, nroleid
                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 15");
             $failed = true;
             break;
         }
@@ -543,6 +627,7 @@ function stats_cron_daily($maxdays=1) {
                 HAVING SUM(statsreads) > 0 OR SUM(statswrites) > 0";
 
         if ($logspresent and !execute_sql($sql, false)) {
+            mtrace("failed query 16");
             $failed = true;
             break;
         }
@@ -556,6 +641,10 @@ function stats_cron_daily($maxdays=1) {
         $nextmidnight = stats_get_next_day_start($nextmidnight);
     }
 
+
+    mtrace("... cleaning temporary tables...");
+    stats_drop_views();
+
     set_cron_lock('statsrunning', null);
 
     if ($failed) {
@@ -830,43 +919,184 @@ function stats_cron_monthly() {
     return true;
 }
 
+require_once($CFG->libdir . '/ddllib.php');
+
+/**
+ * Creates tmp log table
+ * @param timesql string time log condition
+ * @returns boolen success (true) or failure(false)
+ */ 
+function stats_create_logs_view ( $timesql ) {
+
+    global $CFG;
+
+    $table = new XMLDBTable('tmp_stats_log');
+    if ( ! drop_table($table, false, false) ) {
+        mtrace("... error droping tmp_stats_log");
+        return false;
+    }
+
+    if (!execute_sql("CREATE TABLE {$CFG->prefix}tmp_stats_log AS
+                      SELECT * FROM {$CFG->prefix}log l WHERE ".$timesql, false)) {
+        mtrace("...error creating daily SQL temp table, {$CFG->prefix}tmp_stats_log");
+        return false;
+    }
+
+    $table   = new XMLDBTable('tmp_stats_log');
+
+    $i = new XMLDBIndex('tmp_stats_log_time_idx');
+    $i->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('time'));
+    if ( ! add_index($table, $i, false, false) ) {
+        mtrace("... error adding index tmp_stats_log_time_idx");
+        return false;
+    }
+
+    $i = new XMLDBIndex('tmp_stats_log_course_idx');
+    $i->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course'));
+    if ( ! add_index($table, $i, false, false) ) {
+        mtrace("... error adding index tmp_stats_log_time_idx");
+        return false;
+    }
+
+    $i = new XMLDBIndex('tmp_stats_log_action_idx');
+    $i->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('action'));
+    if ( ! add_index($table, $i, false, false) ) {
+        mtrace("... error adding index tmp_stats_log_time_idx");
+        return false;
+    }
+
+    return true;
+}
+
+
+/**
+ * Deletes summary tables for stats calculation
+ */
+
+function stats_drop_views() {
+
+    $table = new XMLDBTable('tmp_stats_log');
+    drop_table($table, false, false);
+    $table = new XMLDBTable('tmp_stats_enrollments');
+    drop_table($table, false, false);
+    $table = new XMLDBTable('tmp_stats_enrollments_na');
+    drop_table($table, false, false);
+    $table = new XMLDBTable('tmp_stats_enrollments_wc');
+    drop_table($table, false, false);
+
+}
+
 /**
- * Returns simplified enrolment sql join data
+ * Creates temporary tables for enrollments 
  * @param int $limit number of max parent course categories
  * @param bool $includedoanything include also admins
  * @return array ra join and where string
  */
-function stats_get_enrolled_sql($limit, $includedoanything) {
+
+function stats_create_enrollments_view ( $limit, $includedoanything, $withcategories=true ) {
+
     global $CFG;
 
-    $adm = $includedoanything ? " OR rc.capability = 'moodle/site:doanything'" : "";
-
-    $join = "JOIN {$CFG->prefix}context ctx
-                  ON ctx.id = ra.contextid
-             CROSS JOIN {$CFG->prefix}course c
-             JOIN {$CFG->prefix}role_capabilities rc
-                  ON rc.roleid = ra.roleid";
-    $where = "((rc.capability = 'moodle/course:view' $adm)
-               AND rc.permission = 1 AND rc.contextid = ".SYSCONTEXTID."
-               AND (ctx.contextlevel = ".CONTEXT_SYSTEM."
-                    OR (c.id = ctx.instanceid AND ctx.contextlevel = ".CONTEXT_COURSE.")";
-
-    for($i=1; $i<=$limit; $i++) {
-        if ($i == 1) {
-            $join .= " LEFT OUTER JOIN {$CFG->prefix}course_categories cc1
-                            ON cc1.id = c.category";
-            $where .= " OR (cc1.id = ctx.instanceid AND ctx.contextlevel = ".CONTEXT_COURSECAT.")";
-        } else {
-            $j = $i-1;
-            $join .= " LEFT OUTER JOIN {$CFG->prefix}course_categories cc$i
-                            ON cc$i.id = cc$j.parent";
-            $where .= " OR (cc$i.id = ctx.instanceid AND ctx.contextlevel = ".CONTEXT_COURSECAT.")";
+    $caps = $includedoanything ? "(rc.capability = 'moodle/course:view' OR rc.capability = 'moodle/site:doanything')" : "rc.capability = 'moodle/course:view'";
+    if ( $withcategories ) {
+        $table_name    = $includedoanything ? "{$CFG->prefix}tmp_stats_enrollments" : "{$CFG->prefix}tmp_stats_enrollments_na";
+        $table_name_wp = $includedoanything ? "tmp_stats_enrollments" : "tmp_stats_enrollments_na";
+    } else {
+        $table_name_wp = "tmp_stats_enrollments_wc";
+        $table_name    = $CFG->prefix . $table_name_wp;
+    }
+
+    // drop + create the table :: faster than deleting
+
+    $table = new XMLDBTable($table_name_wp);
+    if ( ! drop_table($table, false, false) ) {
+        mtrace("... error droping $table_name_wp");
+        return false;
+    }
+    $table = new XMLDBTable($table_name_wp);
+
+    $table->addFieldInfo('roleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
+    $table->addFieldInfo('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
+    $table->addFieldInfo('courseid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
+
+    $table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('roleid','userid','courseid'));
+
+    $table->addIndexInfo('tmp_stats_enrollments_courseid_idx', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
+    $table->addIndexInfo('tmp_stats_enrollments_userid_idx', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+    $table->addIndexInfo('tmp_stats_enrollments_roleid_idx', XMLDB_INDEX_NOTUNIQUE, array('roleid')); 
+
+    if ( ! create_table($table, false, false) ) {
+        mtrace("... error creating {$table_name_wp}");
+        return false;
+    }
+
+    $sql = "INSERT INTO $table_name (roleid, userid, courseid) 
+                SELECT distinct ra.roleid, ra.userid, c.id as courseid 
+                FROM {$CFG->prefix}role_assignments ra JOIN 
+                     {$CFG->prefix}context ctx ON ctx.id = ra.contextid CROSS JOIN 
+                     {$CFG->prefix}course c JOIN 
+                     {$CFG->prefix}role_capabilities rc ON rc.roleid = ra.roleid
+                WHERE $caps AND
+                      rc.permission    = 1 AND 
+                      rc.contextid     = " . SYSCONTEXTID . " AND
+                      ctx.contextlevel = " . CONTEXT_SYSTEM . "
+                UNION
+                SELECT distinct ra.roleid, ra.userid, c.id as courseid 
+                FROM {$CFG->prefix}role_assignments ra JOIN 
+                     {$CFG->prefix}context ctx ON ctx.id = ra.contextid CROSS JOIN 
+                     {$CFG->prefix}course c JOIN 
+                     {$CFG->prefix}role_capabilities rc ON rc.roleid = ra.roleid
+                WHERE $caps AND
+                      rc.permission    = 1 AND 
+                      rc.contextid     = " . SYSCONTEXTID . " AND
+                      c.id             = ctx.instanceid AND 
+                      ctx.contextlevel = " . CONTEXT_COURSE; 
+
+    /** Union for role assignments at course category level
+         */
+
+    if ( $limit >= 1 ) {
+        $join = "";
+        $where =" AND (";
+        for($i=1; $i<=$limit; $i++) {
+            if ($i == 1) {
+                $join .= " LEFT OUTER JOIN {$CFG->prefix}course_categories cc1
+                           ON cc1.id = c.category";
+                $where .= " (cc1.id = ctx.instanceid )";
+            } else {
+                $j = $i-1;
+                $join .= " LEFT OUTER JOIN {$CFG->prefix}course_categories cc$i
+                    ON cc$i.id = cc$j.parent";
+                $where .= " OR (cc$i.id = ctx.instanceid )";
+            }
         }
+
+        $where = $where . ")";
+
+        $sql = $sql . "\nUNION
+            SELECT DISTINCT ra.roleid, ra.userid, c.id as courseid
+            FROM {$CFG->prefix}role_assignments ra
+                JOIN
+                {$CFG->prefix}context ctx ON ctx.id = ra.contextid 
+                CROSS JOIN
+                {$CFG->prefix}course c
+                JOIN {$CFG->prefix}role_capabilities rc  ON rc.roleid = ra.roleid
+                $join
+            WHERE 
+               (rc.capability = 'moodle/course:view' ) AND
+               rc.permission = 1 AND
+               rc.contextid = " . SYSCONTEXTID . " AND
+               ctx.contextlevel = " . CONTEXT_COURSECAT . 
+               $where;
+    }
+
+    if ( ! execute_sql($sql, false) ) {
+        mtrace("... error inserting data");
+        return false;
     }
 
-    $where .= "))";
+    return true;
 
-    return array($join, $where);
 }
 
 /**
