diff --git a/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php b/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php
index 0d89586a6c971..22fa5daad2b3e 100644
--- a/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php
+++ b/vendor/magento/module-catalog/Model/ResourceModel/Category/Collection.php
@@ -8,9 +8,20 @@
 use Magento\Catalog\Model\Category;
 use Magento\Catalog\Model\Product\Visibility;
 use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
+use Magento\Eav\Model\Config;
+use Magento\Eav\Model\ResourceModel\Helper;
 use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
+use Magento\Framework\Data\Collection\EntityFactory;
 use Magento\Framework\DB\Select;
+use Magento\Framework\Event\ManagerInterface;
+use Magento\Framework\Validator\UniversalFactory;
 use Magento\Store\Model\ScopeInterface;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\DB\Ddl\Table;
+use Magento\Store\Model\StoreManagerInterface;
+use Psr\Log\LoggerInterface;
 
 /**
  * Category resource collection
@@ -23,6 +34,10 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
 {
     private const BULK_PROCESSING_LIMIT = 400;
 
+    private const DEFAULT_READ_BATCH_SIZE = 500;
+
+    private const DEFAULT_WRITE_BATCH_SIZE = 2000;
+
     /**
      * Event prefix name
      *
@@ -77,21 +92,33 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
      */
     private $catalogProductVisibility;
 
+    /**
+     * @var int
+     */
+    private int $readBatchSize;
+
+    /**
+     * @var int
+     */
+    private int $writeBatchSize;
+
     /**
      * Constructor
-     * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
-     * @param \Psr\Log\LoggerInterface $logger
-     * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
-     * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Eav\Model\Config $eavConfig
-     * @param \Magento\Framework\App\ResourceConnection $resource
+     * @param EntityFactory $entityFactory
+     * @param LoggerInterface $logger
+     * @param FetchStrategyInterface $fetchStrategy
+     * @param ManagerInterface $eventManager
+     * @param Config $eavConfig
+     * @param ResourceConnection $resource
      * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
-     * @param \Magento\Eav\Model\ResourceModel\Helper $resourceHelper
-     * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
-     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
-     * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
-     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+     * @param Helper $resourceHelper
+     * @param UniversalFactory $universalFactory
+     * @param StoreManagerInterface $storeManager
+     * @param AdapterInterface|null $connection
+     * @param ScopeConfigInterface|null $scopeConfig
      * @param Visibility|null $catalogProductVisibility
+     * @param int|null $readBatchSize
+     * @param int|null $writeBatchSize
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -107,7 +134,9 @@ public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         ?\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
         ?\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null,
-        ?Visibility $catalogProductVisibility = null
+        ?Visibility $catalogProductVisibility = null,
+        ?int $readBatchSize = null,
+        ?int $writeBatchSize = null
     ) {
         parent::__construct(
             $entityFactory,
@@ -126,6 +155,8 @@ public function __construct(
             \Magento\Framework\App\ObjectManager::getInstance()->get(ScopeConfigInterface::class);
         $this->catalogProductVisibility = $catalogProductVisibility ?:
             \Magento\Framework\App\ObjectManager::getInstance()->get(Visibility::class);
+        $this->readBatchSize = $readBatchSize ?: self::DEFAULT_READ_BATCH_SIZE;
+        $this->writeBatchSize = $writeBatchSize ?: self::DEFAULT_WRITE_BATCH_SIZE;
     }
 
     /**
@@ -370,40 +401,96 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr
      * @param array $categoryIds
      * @param int $websiteId
      * @return array
+     * @throws \Zend_Db_Exception
      */
     private function getCountFromCategoryTableBulk(
         array $categoryIds,
         int $websiteId
     ) : array {
-        $subSelect = clone $this->_conn->select();
-        $subSelect->from(['ce2' => $this->getTable('catalog_category_entity')], 'ce2.entity_id')
-            ->where("ce2.path LIKE CONCAT(ce.path, '/%') OR ce2.path = ce.path");
-
-        $select = clone $this->_conn->select();
-        $select->from(
-            ['ce' => $this->getTable('catalog_category_entity')],
-            'ce.entity_id'
-        );
-        $joinCondition =  new \Zend_Db_Expr("cp.category_id IN ({$subSelect})");
-        $select->joinLeft(
-            ['cp' => $this->getProductTable()],
-            $joinCondition,
-            'COUNT(DISTINCT cp.product_id) AS product_count'
-        );
+        $connection = $this->_conn;
+        $tempTableName = 'temp_category_descendants_' . uniqid();
+        $tempTable = $connection->newTable($tempTableName)
+            ->addColumn(
+                'category_id',
+                Table::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false],
+                'Category ID'
+            )
+            ->addColumn(
+                'descendant_id',
+                Table::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false],
+                'Descendant ID'
+            )
+            ->addIndex(
+                $connection->getIndexName($tempTableName, ['category_id', 'descendant_id']),
+                ['category_id', 'descendant_id'],
+                ['type' => AdapterInterface::INDEX_TYPE_PRIMARY]
+            );
+        $connection->createTemporaryTable($tempTable);
+
+        $categoryTable = $this->getTable('catalog_category_entity');
+        foreach (array_chunk($categoryIds, $this->readBatchSize) as $categoryIdsBatch) {
+            $rows = $connection->fetchAll(
+                $connection->select()
+                    ->from($categoryTable, ['entity_id', 'path'])
+                    ->where('entity_id IN (?)', $categoryIdsBatch)
+            );
+
+            $insertData = [];
+
+            foreach ($rows as $row) {
+                $descendantId = (int) $row['entity_id'];
+                $ancestorIds = array_filter(
+                    array_map('intval', explode('/', (string) $row['path']))
+                );
+
+                foreach ($ancestorIds as $ancestorId) {
+                    $insertData[] = [
+                        'category_id' => $ancestorId,
+                        'descendant_id' => $descendantId,
+                    ];
+
+                    if (count($insertData) >= $this->writeBatchSize) {
+                        $connection->insertMultiple($tempTableName, $insertData);
+                        $insertData = [];
+                    }
+                }
+            }
+
+            if ($insertData) {
+                $connection->insertMultiple($tempTableName, $insertData);
+            }
+        }
+
+        $select = $connection->select()
+            ->from(
+                ['t' => $tempTableName],
+                ['category_id' => 't.category_id']
+            )
+            ->joinLeft(
+                ['cp' => $this->getTable('catalog_category_product')],
+                'cp.category_id = t.descendant_id',
+                ['product_count' => 'COUNT(DISTINCT cp.product_id)']
+            );
         if ($websiteId) {
             $select->join(
                 ['w' => $this->getProductWebsiteTable()],
                 'cp.product_id = w.product_id',
                 []
-            )->where(
-                'w.website_id = ?',
-                $websiteId
-            );
+            )->where('w.website_id = ?', $websiteId);
+        }
+        $select->group('t.category_id');
+        $result = $connection->fetchPairs($select);
+        $connection->dropTemporaryTable($tempTableName);
+        $counts = array_fill_keys($categoryIds, 0);
+        foreach ($result as $categoryId => $count) {
+            $counts[$categoryId] = (int)$count;
         }
-        $select->where('ce.entity_id IN(?)', $categoryIds);
-        $select->group('ce.entity_id');
 
-        return $this->_conn->fetchPairs($select);
+        return $counts;
     }
 
     /**
