<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet href="https://dev.horde.org/themes/horde//default/feed-rss.xsl" type="text/xsl"?> 
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> 
 <channel> 
  <title>horde_prefs table access very slow under high usage</title> 
  <pubDate>Fri, 10 Apr 2026 00:42:31 +0000</pubDate> 
  <link>https://bugs.horde.org/ticket/4079</link> 
  <atom:link rel="self" type="application/rss+xml" title="horde_prefs table access very slow under high usage" href="https://bugs.horde.org/ticket/4079/rss" /> 
  <description>horde_prefs table access very slow under high usage</description> 
 
   
   
  <item> 
   <title>

With a few thousand user and a few hundreds simultaneous a</title> 
   <description>

With a few thousand user and a few hundreds simultaneous access to horde, the application becomes too slow.



I tracked down the problem to too many sequential lookup in the table horde_prefs.

At peak hours, the same type of SQL request start to pile up in the database :



  SELECT pref_scope, pref_name, pref_value FROM horde_prefs WHERE pref_uid = &#039;xxxx&#039;  AND (pref_scope = &#039;horde&#039; OR pref_scope = &#039;horde&#039;) ORDER BY pref_scope



In our database, this table containe over 62000 entries.



In pg_stat_user_tables (a system view providing detailed statistics of database usage in PostgreSQL), we can see a high rate of sequential lookups :



 relid | schemaname |          relname          | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del 

 16416 | public     | horde_prefs               |   128826 |   8010852425 |          |               |        47 |      3512 | 0



Other thing to notice is there is no index used.





The SQL creation script confirms that the table horde_prefs is not using any index.





Creating two indexes solved the problem.

(see attached patch)



Environment : 

OS  : FreeBSD 6.0-Release-p6

Horde : 3.1.1

DB : postgresql 8.1.4</description> 
   <pubDate>Mon, 26 Jun 2006 10:32:56 +0000</pubDate> 
   <link>https://bugs.horde.org/ticket/4079#t21418</link> 
  </item> 
   
  <item> 
   <title>&gt; At peak hours, the same type of SQL request start to pile </title> 
   <description>&gt; At peak hours, the same type of SQL request start to pile up in the 

&gt; database :

&gt;

&gt;   SELECT pref_scope, pref_name, pref_value FROM horde_prefs WHERE 

&gt; pref_uid = &#039;xxxx&#039;  AND (pref_scope = &#039;horde&#039; OR pref_scope = &#039;horde&#039;) 

&gt; ORDER BY pref_scope



Doh, looks like the preference cache was broken in Horde 3.1.1, and noone noticed so far. Fixed in CVS.



&gt; In pg_stat_user_tables (a system view providing detailed statistics 

&gt; of database usage in PostgreSQL), we can see a high rate of 

&gt; sequential lookups :

&gt;

&gt;  relid | schemaname |          relname          | seq_scan | 

&gt; seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | 

&gt; n_tup_del

&gt;  16416 | public     | horde_prefs               |   128826 |   

&gt; 8010852425 |          |               |        47 |      3512 | 0

&gt;

&gt; Other thing to notice is there is no index used.

&gt;

&gt;

&gt; The SQL creation script confirms that the table horde_prefs is not 

&gt; using any index.



That&#039;s not true, there is even a primary key. I don&#039;t know PostgreSQL well enough to understand its EXPLAIN results, but on MySQL it clearly shows that the primary key index is used.</description> 
   <pubDate>Wed, 28 Jun 2006 22:58:44 +0000</pubDate> 
   <link>https://bugs.horde.org/ticket/4079#t21471</link> 
  </item> 
   
  <item> 
   <title>&gt;&gt; At peak hours, the same type of SQL request start to pile</title> 
   <description>&gt;&gt; At peak hours, the same type of SQL request start to pile up in the

&gt;&gt; database :

&gt;&gt;

&gt;&gt;   SELECT pref_scope, pref_name, pref_value FROM horde_prefs WHERE

&gt;&gt; pref_uid = &#039;xxxx&#039;  AND (pref_scope = &#039;horde&#039; OR pref_scope = &#039;horde&#039;)

&gt;&gt; ORDER BY pref_scope

&gt;

&gt; Doh, looks like the preference cache was broken in Horde 3.1.1, and 

&gt; noone noticed so far. Fixed in CVS.



95% of the queries accumulating were for new sessions (no preference cache yet anyway). Even without preference caching, the performance problem disappeared after creating the indexes. 



&gt;&gt; In pg_stat_user_tables (a system view providing detailed statistics

&gt;&gt; of database usage in PostgreSQL), we can see a high rate of

&gt;&gt; sequential lookups :

&gt;&gt;

&gt;&gt;  relid | schemaname |          relname          | seq_scan |

&gt;&gt; seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd |

&gt;&gt; n_tup_del

&gt;&gt;  16416 | public     | horde_prefs               |   128826 |

&gt;&gt; 8010852425 |          |               |        47 |      3512 | 0

&gt;&gt;

&gt;&gt; Other thing to notice is there is no index used.

&gt;&gt;

&gt;&gt;

&gt;&gt; The SQL creation script confirms that the table horde_prefs is not

&gt;&gt; using any index.

&gt; That&#039;s not true, there is even a primary key. I don&#039;t know PostgreSQL 

My mistake, I should have said &quot;for this particular type of query&quot;



&gt; well enough to understand its EXPLAIN results, but on MySQL it 

&gt; clearly shows that the primary key index is used.



horde=# explain SELECT pref_scope, pref_name, pref_value FROM horde_prefs WHERE pref_uid = &#039;jean&#039; AND (pref_scope = &#039;horde&#039; OR pref_scope = &#039;horde&#039;) ORDER BY pref_scope  ;

                                      QUERY PLAN                                      

--------------------------------------------------------------------------------------

 Sort  (cost=5315.06..5315.07 rows=4 width=96)

   Sort Key: pref_scope

   -&gt;  Seq Scan on horde_prefs  (cost=0.00..5315.02 rows=4 width=96)

         Filter: (((pref_uid)::text = &#039;jean&#039;::text) AND (pref_scope = &#039;horde&#039;::text))

(4 rows)



The EXPLAIN output is clear enough. It says &#039;Sequential Scan&#039; with a huge cost.



Compare with the same query after creating the two indexes :



horde=# explain SELECT pref_scope, pref_name, pref_value FROM horde_prefs WHERE pref_uid = &#039;jean&#039; AND (pref_scope = &#039;horde&#039; OR pref_scope = &#039;horde&#039;) ORDER BY pref_scope  ;

                                   QUERY PLAN

---------------------------------------------------------------------------------

 Sort  (cost=32.08..32.08 rows=2 width=72)

   Sort Key: pref_scope

   -&gt;  Bitmap Heap Scan on horde_prefs  (cost=2.03..32.07 rows=2 width=72)

         Recheck Cond: ((pref_uid)::text = &#039;jean&#039;::text)

         Filter: (pref_scope = &#039;horde&#039;::text)

         -&gt;  Bitmap Index Scan on pref_uid_idx  (cost=0.00..2.03 rows=8 width=0)

               Index Cond: ((pref_uid)::text = &#039;jean&#039;::text)

(7 rows)



The primary key is made of the following fields (from  horde/scripts/sql/horde_prefs.sql) :



   PRIMARY KEY (pref_uid, pref_scope, pref_name)



But, the query doesn&#039;t mention pref_name, only pref_uid and pref_scope.



I guess creating those 2 indexes (pref_uid_idx and pref_scope_idx) won&#039;t hurt, even in MySQL.



</description> 
   <pubDate>Thu, 29 Jun 2006 13:55:44 +0000</pubDate> 
   <link>https://bugs.horde.org/ticket/4079#t21514</link> 
  </item> 
   
  <item> 
   <title>I tested again with MySQL, and it also improves performance </title> 
   <description>I tested again with MySQL, and it also improves performance there a bit, even though not nearly as much as with PostgreSQL.

The indexes have been added to all SQL scripts now.</description> 
   <pubDate>Thu, 29 Jun 2006 16:24:19 +0000</pubDate> 
   <link>https://bugs.horde.org/ticket/4079#t21517</link> 
  </item> 
   
  <item> 
   <title>MySQL does not use either of these indexes and always uses t</title> 
   <description>MySQL does not use either of these indexes and always uses the primary key index.  Chuck confirms this.  I also tested Oracle:



SQL&gt; set autotrace traceonly explain



With only the primary key index, the explain output is:



Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=35)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF &#039;HORDE_PREFS&#039; (Cost=4 Card=1 Bytes=35)

   2    1     INDEX (RANGE SCAN) OF &#039;PK_HORDE_PREFS&#039; (UNIQUE) (Cost=3 Card=1)



With the addition of the two one-column indexes, the explain output is:



Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=35)

   1    0   SORT (ORDER BY) (Cost=4 Card=1 Bytes=35)

   2    1     TABLE ACCESS (BY INDEX ROWID) OF &#039;HORDE_PREFS&#039; (Cost=2 Card=1 Bytes=35)

   3    2       INDEX (RANGE SCAN) OF &#039;PREF_UID_IDX&#039; (NON-UNIQUE) (Cost=1 Card=6)



With the addition of one two-column index, the explain output is:



Execution Plan

----------------------------------------------------------

   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=35)

   1    0   TABLE ACCESS (BY INDEX ROWID) OF &#039;HORDE_PREFS&#039; (Cost=2 Card=1 Bytes=35)

   2    1     INDEX (RANGE SCAN) OF &#039;PREF_UID_SCOPE_IDX&#039; (NON-UNIQUE) (Cost=1 Card=1)

</description> 
   <pubDate>Fri, 30 Jun 2006 21:30:02 +0000</pubDate> 
   <link>https://bugs.horde.org/ticket/4079#t21531</link> 
  </item> 
   
   
 
 </channel> 
</rss> 
