magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.45k stars 9.29k forks source link

Slow processing of attributes with Table source_model #38934

Open martin-cod opened 1 month ago

martin-cod commented 1 month ago

Summary

When working with product collections I found out that getting attribute values is very slow because of using method \Magento\Eav\Model\Entity\Attribute\Source\Table::getSpecificOptions. This method is not optimized to work with product collections because it loads data from Database every time attribute value is requested. Taking in mind that \Magento\Eav\Model\Entity\Attribute\Source\Table is a default source model for any attribute which has no source_model defined in eav_attribute table it brings a siriouse performance degradation. For example, when working with attribute of text frontend_input type it uses getSpecificOptions() method which returns empty response every time.

To get attribute value there 2 possible loading stacks.

Stack 1. Performance degradation is detected for only attributes of select, multiselect frontend_input type

1. \Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend::getValue
2. \Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend::getOption
3. \Magento\Eav\Model\Entity\Attribute\Source\Table::getOptionText
4. \Magento\Eav\Model\Entity\Attribute\Source\Table::getSpecificOptions

Stack 2. Performance degradation is detected for all attribute regardless of frontend_input type

1. \Magento\Catalog\Model\Product::getAttributeText
2. \Magento\Eav\Model\Entity\Attribute\Source\Table::getOptionText
3. \Magento\Eav\Model\Entity\Attribute\Source\Table::getSpecificOptions

Examples

See Summary section with explanations

Proposed solution

Use \Magento\Eav\Model\Entity\Attribute\Source\Table::getAllOptions call in getSpecificOptions method, so it will minimize the number of SQL queries to 1 per attribute per product collection because option values in getAllOptions method are cached

public function getSpecificOptions($ids, $withEmpty = true) {
    $allOptions = $this->getAllOptions(false);
    $specificOptions = [];

    if (is_string($ids) && strpos($ids, ',') !== false) {
        $ids = explode(',', $ids);
    }

    if (!is_array($ids)) {
        $ids = (array)$ids;
    }

    if (count($allOptions) > 0) {
        foreach ($allOptions as $option) {
            if (isset($option['value']) && in_array($option['value'], $ids)) {
                $specificOptions[] = $option;
            }
        }
    }

    if ($withEmpty) {
        $specificOptions = $this->addEmptyOption($specificOptions);
    }

    return $specificOptions;
}

Release note

No response

Triage and priority

m2-assistant[bot] commented 1 month ago

Hi @martin-cod. Thank you for your report. To speed up processing of this issue, make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, Add a comment to the issue: