-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[com_fields] Fetch all custom field values in one query #14558
Conversation
$fieldsQuery = $this->getDbo()->getQuery(true); | ||
$fieldsQuery->select($fieldsQuery->qn('id')) | ||
->from($fieldsQuery->qn('#__fields')) | ||
->where($fieldsQuery->qn('context') . ' = ' . $fieldsQuery->q($context)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks wrong to me as you have removed context from the db table ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That query is against #__fields and not #__fields_values. It is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah thanks i got confused. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if we use in the core a delete with an inner join as subselects are slower? I couldn't find a way to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know that we use it. But that does not mean that we don't use it. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not that concerned about performance for deleting fields. It's not done multiple times per second usually. Much more important that it works reliably 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@laoneo in com_finder there is something similar https://github.com/joomla/joomla-cms/blob/staging/administrator/components/com_finder/helpers/indexer/taxonomy.php#L345
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw that, but also doesn't use an inner join.
} | ||
|
||
if ($field->value === '' || $field->value === null) | ||
if (!isset($field->value) || $field->value === '' || $field->value === null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$field->value === null
this will never happen. isset()
will check that.
Thanks @csthomas removed the double null check. |
@@ -66,11 +66,9 @@ CREATE TABLE IF NOT EXISTS `#__fields_groups` ( | |||
|
|||
CREATE TABLE IF NOT EXISTS `#__fields_values` ( | |||
`field_id` int(10) unsigned NOT NULL, | |||
`context` varchar(255) NOT NULL, | |||
`item_id` varchar(255) NOT NULL COMMENT 'Allow references to items which have strings as ids, eg. none db systems.', | |||
`value` text NOT NULL DEFAULT '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are not changed it now, but database field with type TEXT NOT NULL can not have default value on mysql.
https://dev.mysql.com/doc/refman/5.7/en/blob.html
There is a lot of such mistakes in joomla but please do not repeat it.
I see 2 solutions. Allow to NULL or always set default value in php code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sort of stuff should be done in a separate pr, basically on thing in one pr, otherwise it gets harder to review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I want only mention about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem.
@@ -109,7 +109,7 @@ protected function getStoreId($id = '') | |||
$id .= ':' . serialize($this->getState('filter.assigned_cat_ids')); | |||
$id .= ':' . $this->getState('filter.state'); | |||
$id .= ':' . $this->getState('filter.group_id'); | |||
$id .= ':' . print_r($this->getState('filter.language'), true); | |||
$id .= ':' . serialize($this->getState('filter.language')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
serialize? :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not, it is an array and serialize is also used for the assigned cats.
|
||
if (!key_exists($key, $this->valueCache)) | ||
{ | ||
$this->valueCache[$key] = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I read the code correctly, this line is not needed. You set $this->valueCache[$key] = $data; later already
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True
|
||
$query->select(array($query->qn('field_id'), $query->qn('value'))) | ||
->from($query->qn('#__fields_values')) | ||
->where($query->qn('field_id') . ' in (' . implode(',', ArrayHelper::toInteger($fieldIds)) . ')') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be IN instead of in. Am I correct that we always use upper case string for SQL keywords?
After thinking about this a bit, the only question I have is if we really need both the "getFieldValue" and "getFieldValues" methods. They do quite the same just instead of using a "->where field_id IN (...)" instead of "->where field_id = ...". |
Please don't combine the two. That violates SRP. |
Stupid question, what is SRP? |
single responsibility prinzip |
Makes sense 😄 So better to have a method to fetch the value(s) for a single field and one for fetching values for multiple fields allthough they do basically the same thing? |
Right. Basically you want your methods to be responsible for one task and one task only. Fetching the data for a single field and fetching the data for multiple fields are two different tasks, will presumably have two different return types (one might be a value object and the other may be a collection of value objects), and may be post-processed by two different code paths (even if you're doing a foreach loop and it just calls the path for the single item, it still has to have that extra logic). So it's better from a structural standpoint to separate those out. |
Changed the getValue function to use getValues and removed the not needed code as pointed out by @joomdonation. Additionally added some inline comments to explain what the function is doing. |
@laoneo when you on it could you fix the code style issues |
@rdeutz which ones? Travis is running trough. |
Ah sorry, didn't realize that drone is now doing the CS stuff. Give me a minute. |
done @laoneo |
@rdeutz all good now. |
Should we also add here a release blocker label as it reduces the amount of SQL queries? |
Added due to the major performance issues this PR aims to address. |
I have tested this item 🔴 unsuccessfully on c2af37b
Access to that menu item, see this error 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') AND The actual SQL command is SELECT Look like in some condition, field_id doesn't have any data for some reasons This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14558. |
BTW, in my test, look like the custom fields are not being displayed for Category Blog menu option. So in that case, could we stop querying the database to get data? (I haven't tested this feature much so far, so maybe I just mis-understand how it works) |
I don't think I would hardcode the plugin context to exclude category views. In theory someone could do a category layout using fields if desired. |
OK. That makes sense (although with default usage like this, it is a waste of resource to query data without using it - It might has performance impact). Also, one thing about category view which I cannot test right now because above error. Before patch, for each item, an SQL query is is generated to get data for a field, so with 2 articles, 2 fields, 4 query total. I guess if this patch works, there will only one query for one article, so still 2 query. Do we want to merge it to one query to get data for all custom fields of all articles (not sure if it is possible) |
Not possible with the current plugin events. You would need a new event for the whole list. |
@joomdonation I'v added a test if the field ids are empty. Now the error should be gone. |
I have tested this item ✅ successfully on 23fac40 This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14558. |
OK. It works now. Unrelated to this PR, on category blog page, still one query per article if you want to improve (in case it can be improved) |
Open an issue for it. But as @Bakual said, it needs a new event for it, probably not a bad idea, but I'm not sure if it is doable in the 3 series. |
I have tested this item ✅ successfully on 23fac40 This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14558. |
This is much better but still not quite there (not the fault of this PR), we have the same problem with tags. This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14558. |
Guess RTC? |
work now with Falang |
Pull Request for Issue #14473.
Summary of Changes
Right now when the values of the fields are fetched, for every field a query is done. This pr changes the behavior to one query for all fields.
Integer indexes are faster to lookup than string indexes, the context column got removed from the field_values table, we gain a bit of performance here as well.
Ping @Bakual and @mbabker for review.
Ping @alikon and @csthomas did I change the installer and upgrade scripts correctly?
Testing Instructions
Expected result
All of these should work as before, but with less queries. When the debugging is on, then you should see less queries logged.
Actual result
It works, but with more queries.
Documentation Changes Required
None.