Joomla 3.9
When viewing the Action logs, there is a filter for the User.
On a site with a million unique users having actions - this will load all million usernames into a select list which will render a page with a huge size.
No where else in Joomla do we attempt to load a million items in a dropdown.
Labels |
Added:
?
|
Title |
|
Labels |
Added:
J3 Issue
|
but thats the point - you might well have 10 million registered users on your site, of which only 1 million logged in users have done something that creates an entry in the log, and therefore there will be 1 million users in the dropdown because they have actions.
No where else in Joomla would this be the case. Anywhere else we need to select a user its done in a modal view
No where else in Joomla would this be the case. Anywhere else we need to select a user its done in a modal view
Actually the filter by author option in the article manager works exactly the same way
Actually the filter by author option in the article manager works exactly the same way
But there will never be a million Authors on a Joomla site. No where else in Joomla would you load a million options into a dropdown on purpose.
There is a HUGE possibility that a Joomla 3.9 site could have action logs for a million users (real users, or just spam users). In fact until my review there were no indexes on these tables at all, the performance would have been undeniably slow.
Note to self: test the performance of this sql query too
On a related subject, the join to the users table for the main action log list is only needed if you're doing a search by username.
diff --git a/administrator/components/com_actionlogs/models/actionlogs.php b/administrator/components/com_actionlogs/models/actionlogs.php
index dddf2703d4..d187f8863c 100644
--- a/administrator/components/com_actionlogs/models/actionlogs.php
+++ b/administrator/components/com_actionlogs/models/actionlogs.php
@@ -85,8 +85,7 @@ class ActionlogsModelActionlogs extends JModelList
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('a.*, u.name')
- ->from('#__action_logs AS a')
- ->leftJoin('#__users AS u ON a.user_id = u.id');
+ ->from('#__action_logs AS a');
// Get ordering
$fullorderCol = $this->state->get('list.fullordering', 'a.id DESC');
@@ -149,6 +148,7 @@ class ActionlogsModelActionlogs extends JModelList
else
{
$search = $db->quote('%' . $db->escape($search, true) . '%');
+ $query->leftJoin('#__users AS u ON a.user_id = u.id');
$query->where('(' . $db->quoteName('u.username') . ' LIKE ' . $search . ')');
}
}
So discussing this with @mbabker offline, there are several things that need to happen
There are two main pain points.
Example sql:
SELECT `u`.`id` AS `value`,`u`.`name` AS `text`
FROM `t0159_users` AS `u`
INNER JOIN `t0159_action_logs` AS `c`
ON `c`.`user_id` = `u`.`id`
GROUP BY `u`.`id`,`u`.`name`
ORDER BY `u`.`name`
47000 rows gives:
The reason for this is that it doesn't scale.
The sql queries to power it are slow, and it will load a new row per user who has a user action log. Plus if you are really interested in looking at a specific user you can use the search box to search on their username easily (and more important, with performance).
With 8,000 users with actions, this takes just under 50ms
With 11,000 users with actions, this takes just under 200ms
with 32,000 users with actions, this takes 538.64ms
with 41,000 users with actions, this takes 765.22ms
with 48,000 users with actions, this takes 801ms
With 32,000 users, on clicking the users dropdown (chosen) it takes 9 seconds to open (iMac Google Chrome, untested in other browsers), and the page size is approx 3Mb in size.
Example SQL:
SELECT COUNT(*)
FROM t0159_action_logs AS a
LEFT JOIN t0159_users AS u
ON a.user_id = u.id
@mabbker says "the join to the users table for the main action log list is only needed if you're doing a search by username."
As the username is already stored in the JSON and the userid is already stored in the action log row, there is no need to do a massive join of the users table. Alternatively as @mbabker states, the username could be stored in its own column in the __action_logs table removing the need for the join. This also allows you to retain data about the user when the user is deleted using User Manager
with 1 million rows you might regret selecting this :)
ok I failed today to get 1 million rows - but I did get enough to show the slow performance (~113090 rows, of unique users logging in - not un-reasonable for a large Joomla site) - (Also highlights other performance issues with large CSV exports.)
If you want to replicate these issues, you can grab a copy of my full db here http://screenshot.myjoom.la/3dd57411d692
The super admin credentials are admin/admin and the database prefix for your configuration.php after importing the sql is t0159_
_Edit: The data in the above database is all fictitious. The IP addresses, usernames, names, and passwords are all faked (and no real people were harmed in its making), and yes I know I forgot to hash the passwords on the faked users :-)
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2019-02-10 21:34:25 |
Closed_By | ⇒ | PhilETaylor |
I always get my joins backwards but it looks like the intent is to limit to those who have log actions, see here. So might just be wrong join.