Why Indexers Exist

Magento keeps product data in EAV and serves it from flat index tables; indexers are the processes that build those tables.

Syntaxbin/magento indexer:info

A product's fields do not live in one row. Magento stores them in EAV (entity-attribute-value), where each value sits in a side table keyed by attribute: catalog_product_entity_varchar, catalog_product_entity_decimal, and so on. That is flexible for the admin and slow for a category page, which would otherwise need a join per attribute per product.

What an indexer is

An indexer is a process that precomputes. It reads the normalised data once and writes a flat table the storefront can query cheaply. The catalog_product_price indexer fills catalog_product_index_price. The catalog_category_product indexer fills the category-to-product map. The storefront reads the index, not the EAV tables.

What 2.4.9 ships

Run bin/magento indexer:info for the list on your install. Magento Open Source 2.4.9 declares design_config_grid, customer_grid, catalog_category_product, catalog_product_category, catalog_product_price, catalog_product_attribute, catalogrule_rule, catalogrule_product, cataloginventory_stock, inventory and catalogsearch_fulltext.

Where the time goes

The index is a copy. Change the data and the copy is stale until something rebuilds it. If you updated a price with raw SQL, nothing told the indexer and the storefront keeps the old number. Run bin/magento indexer:reindex catalog_product_price, then bin/magento cache:flush, before deciding your code is broken. A full rebuild of everything is bin/magento indexer:reindex with no arguments.

Example

Example · xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- vendor/magento/module-catalog/etc/indexer.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
    <indexer id="catalog_product_flat" view_id="catalog_product_flat"
             class="Magento\Catalog\Model\Indexer\Product\Flat">
        <title translate="true">Product Flat Data</title>
        <description translate="true">Reorganize EAV product structure to flat structure</description>
    </indexer>
    <indexer id="catalog_category_product" view_id="catalog_category_product"
             class="Magento\Catalog\Model\Indexer\Category\Product" shared_index="category_product">
        <title translate="true">Category Products</title>
        <description translate="true">Indexed category/products association</description>
    </indexer>
    <indexer id="catalog_product_category" view_id="catalog_product_category"
             class="Magento\Catalog\Model\Indexer\Product\Category" shared_index="category_product">
        <title translate="true">Product Categories</title>
        <description translate="true">Indexed product/categories association</description>
    </indexer>
    <indexer id="catalog_product_price" view_id="catalog_product_price"
             class="Magento\Catalog\Model\Indexer\Product\Price">
        <title translate="true">Product Price</title>
        <description translate="true">Index product prices</description>
    </indexer>
    <indexer id="catalog_product_attribute" view_id="catalog_product_attribute"
             class="Magento\Catalog\Model\Indexer\Product\Eav">
        <title translate="true">Product EAV</title>
        <description translate="true">Index product EAV</description>
    </indexer>
</config>

When to use it

  • Explaining to a merchant why a price edited in the admin has not changed on the category page.
  • Finding which index table a slow product listing query is actually reading.
  • Confirming after a deployment that every indexer is ready before letting traffic in.
  • Deciding whether a reporting query should read EAV live or get its own index.

More examples

Listing and checking the indexers

indexer:info prints the indexer id on the left and its title on the right. The id is what every other command takes as an argument, and what you will see in indexer.xml. Reach for this first on an unfamiliar install, because third-party modules add their own ids here.

Example · bash
$ bin/magento indexer:info
design_config_grid                       Design Config Grid
customer_grid                            Customer Grid
catalog_category_product                 Category Products
catalog_product_category                 Product Categories
catalog_product_price                    Product Price
catalog_product_attribute                Product EAV
catalogrule_rule                         Catalog Rule Product
catalogrule_product                      Catalog Product Rule
cataloginventory_stock                   Stock
inventory                                Inventory
catalogsearch_fulltext                   Catalog Search

One indexer declaring a dependency on another

Magento_CatalogRule declares two indexers of its own, then reopens catalog_product_price, an indexer owned by Magento_Catalog, to add a dependency. Indexer declarations from every module are merged into one configuration, so a module can add dependencies without touching another module's file. The dependency means the price index is only rebuilt by cron once catalogrule_rule has caught up, because a catalog price rule changes the price.

Example · xml
<?xml version="1.0"?>
<!-- vendor/magento/module-catalog-rule/etc/indexer.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
    <indexer id="catalogrule_rule" view_id="catalogrule_rule"
             class="Magento\CatalogRule\Model\Indexer\Rule\RuleProductIndexer"
             shared_index="catalogrule">
        <title translate="true">Catalog Rule Product</title>
        <description translate="true">Indexed rule/product association</description>
    </indexer>
    <indexer id="catalogrule_product" view_id="catalogrule_product"
             class="Magento\CatalogRule\Model\Indexer\Product\ProductRuleIndexer"
             shared_index="catalogrule">
        <title translate="true">Catalog Product Rule</title>
        <description translate="true">Indexed product/rule association</description>
    </indexer>
    <indexer id="catalog_product_price">
        <dependencies>
            <indexer id="catalogrule_rule" />
        </dependencies>
    </indexer>
</config>

What a full reindex prints

Reindexing writes new rows into the index tables. It does not, by itself, guarantee the page you are looking at is regenerated, because whole pages are cached in the full_page type. Pair a manual reindex with a cache flush while you are developing, so you are not debugging a cached response.

Example · bash
$ bin/magento indexer:reindex catalog_product_price catalog_category_product
Product Price index has been rebuilt successfully in 00:00:47
Category Products index has been rebuilt successfully in 00:00:12

$ bin/magento cache:flush
Flushed cache types:
config
layout
block_html
collections
reflection
db_ddl
compiled_config
eav
customer_notification
config_integration
config_integration_api
config_webservice
translate
full_page

Discussion

  • Be the first to comment on this lesson.