[TikiWiki-commits] [Git][tikiwiki/tiki][29.x] [FIX] manticore and relation field optimizations - cache relation titles on...

"Victor Emanouilov \(@kroky\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <69440f9d9cf6a_2918001093788@gitlab-sidekiq-low-urgency-cpu-bound-v2-cc8779578-zg78z.mail>

Victor Emanouilov pushed to branch 29.x at Tiki Wiki CMS Groupware / Tiki


Commits:
5e020fd6 by Victor Emanouilov at 2025-12-18T16:28:35+02:00
[FIX] manticore and relation field optimizations - cache relation titles on intput/output of the field when they are more than 1 to fix the N+1 query problem, cache possible facet fields to spare the additional describe query for each manticore query

- - - - -


3 changed files:

- lib/core/Search/Manticore/PdoClient.php
- lib/core/Tracker/Field/Relation.php
- lib/objectlib.php


Changes:

=====================================
lib/core/Search/Manticore/PdoClient.php
=====================================
@@ -195,6 +195,10 @@ class PdoClient
 
     public function possibleFacetFields($table)
     {
+        static $cache = [];
+        if (isset($cache[$table])) {
+            return $cache[$table];
+        }
         if ($table == self::distributedIndexName()) {
             $stmt = $this->query("DESC $table");
             $result = $stmt->fetchAll();
@@ -220,7 +224,8 @@ class PdoClient
             }
         }
         if (count($fields) == 1) {
-            return array_keys(array_shift($fields));
+            $cache[$table] = array_keys(array_shift($fields));
+            return $cache[$table];
         }
         $common = [];
         $result = array_shift($fields);
@@ -241,7 +246,8 @@ class PdoClient
             }
             $common[] = $field;
         }
-        return $common;
+        $cache[$table] = $common;
+        return $cache[$table];
     }
 
     public function deleteIndex($index)


=====================================
lib/core/Tracker/Field/Relation.php
=====================================
@@ -224,6 +224,11 @@ class Tracker_Field_Relation extends \Tracker\Field\AbstractItemField implements
 
         $data = $this->getFieldData();
 
+        if (! empty($data['relations']) && count($data['relations']) > 1) {
+            // cache the titles with just 1 query for all related objects
+            $this->getItemValues();
+        }
+
         $filter = $this->trackerField->getParsedFilter();
 
         if (
@@ -292,25 +297,20 @@ class Tracker_Field_Relation extends \Tracker\Field\AbstractItemField implements
                 return ! empty($returnValue) ? $returnValue : $itemData;
             }
             return $this->getConfiguration('value');
-        } elseif ($context['list_mode'] === 'text') {
-            return implode(
-                "\n",
-                array_map(
-                    function ($rel) {
-                        return $rel->target->getTitle($this->trackerField->getOption('format'));
-                    },
-                    $this->getObjectRelationInstances()
-                )
-            );
         } else {
+            $relations = $this->getObjectRelationInstances();
+            if (! empty($relations) && count($relations) > 1) {
+                // cache the titles with just 1 query for all related objects
+                $this->getItemValues();
+            }
             // TODO: render metadata as well
             return implode(
-                "<br/>",
+                $context['list_mode'] === 'text' ? "\n" : '<br/>',
                 array_map(
                     function ($rel) {
                         return $rel->target->getTitle($this->trackerField->getOption('format'));
                     },
-                    $this->getObjectRelationInstances()
+                    $relations
                 )
             );
         }
@@ -318,6 +318,7 @@ class Tracker_Field_Relation extends \Tracker\Field\AbstractItemField implements
 
     public function renderOutput($context = [])
     {
+        $this->getItemValues(); // this caches the titles and is faster as it does 1 query for all related objects
         $list_mode = $context['list_mode'] ?? '';
         if ($list_mode === 'csv' || $list_mode === 'text') {
             return $this->renderInnerOutput($context);
@@ -337,6 +338,10 @@ class Tracker_Field_Relation extends \Tracker\Field\AbstractItemField implements
                 }
             }
             $relations = array_values($relations);
+            if (! empty($relations) && count($relations) > 1) {
+                // cache the titles with just 1 query for all related objects
+                $this->getItemValues();
+            }
 
             return $this->renderTemplate(
                 'trackeroutput/relation.tpl',


=====================================
lib/objectlib.php
=====================================
@@ -30,6 +30,8 @@ class ObjectLib extends TikiLib
     'comments_locked'//?
     ];
 
+    public static $titleCache = [];
+
     /**
      *  Create an object record for the given Tiki object if one doesn't already exist.
      * Returns the object record OID. If the designated object does not exist, may return NULL.
@@ -932,6 +934,26 @@ class ObjectLib extends TikiLib
         if (empty($objects)) {
             return [];
         }
+        $itemsValues = [];
+        if (ObjectLib::$titleCache) {
+            foreach ($objects as $key => $object) {
+                $cacheKey = $object['type'] . ':' . $object['id'] . ':' . $format;
+                if (isset(ObjectLib::$titleCache[$cacheKey])) {
+                    $itemsValues[] = [
+                        'object_type' => $object['type'],
+                        'object_id' => $object['id'],
+                        'title' => ObjectLib::$titleCache[$cacheKey],
+                    ];
+                    unset($objects[$key]);
+                }
+            }
+        }
+        if (empty($objects)) {
+            return $itemsValues;
+        }
+        if (TikiLib::lib('tiki')->isMemoryLow()) {
+            ObjectLib::$titleCache = [];
+        }
         $lib = TikiLib::lib('unifiedsearch');
         $metaItemIds = [];
         $query = $lib->buildQuery([]);
@@ -960,7 +982,6 @@ class ObjectLib extends TikiLib
                 }
             }
         }
-        $itemsValues = [];
         foreach ($result as $item) {
             $values = [
                 'object_type' => $item['object_type'],
@@ -982,6 +1003,8 @@ class ObjectLib extends TikiLib
                     return '';
                 }
             }, $format);
+            $cacheKey = $item['object_type'] . ':' . $item['object_id'] . ':' . $format;
+            ObjectLib::$titleCache[$cacheKey] = $values['title'];
             $itemsValues[] = $values;
         }
         return $itemsValues;
@@ -1017,6 +1040,13 @@ class ObjectLib extends TikiLib
     public function getFormattedTitle(string $type, string $id, ?string $defaultTitle, ?string $format = '', ?string $extra = '', ?string $metaItemId = null): string
     {
         if ($format) {
+            $cacheKey = $type . ':' . $id . ':' . $format;
+            if (isset(ObjectLib::$titleCache[$cacheKey])) {
+                return ObjectLib::$titleCache[$cacheKey];
+            }
+            if (TikiLib::lib('tiki')->isMemoryLow()) {
+                ObjectLib::$titleCache = [];
+            }
             $lib = TikiLib::lib('unifiedsearch');
             if ($metaItemId) {
                 $query = $lib->buildQuery([
@@ -1053,6 +1083,7 @@ class ObjectLib extends TikiLib
             });
             $titles = $result->getArrayCopy();
             $title = array_shift($titles);
+            ObjectLib::$titleCache[$cacheKey] = $title;
         } else {
             $title = $defaultTitle;
         }



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5e020fd668bd606d7984076d4beb657271523199

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5e020fd668bd606d7984076d4beb657271523199
You're receiving this email because of your account on gitlab.com.

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.