The following is from file-storage/www/folder-list-postgresql.xql, a file which no longer exists on HEAD. It's running very slowly in one of my sites:
select lpad(' ',12 * tree_level(i.tree_sortkey),' ') as spaces,
(select f.label from cr_folders f where f.folder_id = i.item_id) as label,
(select f.folder_id from cr_folders f where f.folder_id = i.item_id) as new_parent
from cr_items i, cr_items l
where acs_permission__permission_p(i.item_id,'0','write')
and exists (select 1 from cr_folders f where f.folder_id = i.item_id)
and not exists (select 1
from cr_items j, cr_items k
where i.item_id = j.item_id
and j.item_id != '78948'
and j.tree_sortkey between k.tree_sortkey and tree_right(k.tree_sortkey)
and k.item_id = '78948')
and i.tree_sortkey between l.tree_sortkey and tree_right(l.tree_sortkey)
and l.item_id = file_storage__get_root_folder('522')
order by i.tree_sortkey;
I did some searches and found a few suggestions to use "in" instead of "exists", so I tried changing the middle clause to use "and 1 not in " but it only helped slightly.
My hope was that this would have been optimized already in a newer version of OpenACS, but instead it has been removed. Maybe that means it can't be made better?
Explain Analyze says
Sort (cost=30476.68..30477.01 rows=132 width=15) (actual time=25913.139..25913.169 rows=15 loops=1)
Sort Key: i.tree_sortkey
Sort Method: quicksort Memory: 18kB
-> Nested Loop (cost=0.50..30472.03 rows=132 width=15) (actual time=19.707..25912.730 rows=15 loops=1)
-> Index Scan using cr_items_pk on cr_items l (cost=0.25..8.52 rows=1 width=11) (actual time=0.342..0.348 rows=1 loops=1)
Index Cond: (item_id = file_storage__get_root_folder(522))
-> Index Scan using cr_sortkey_idx on cr_items i (cost=0.25..30041.77 rows=132 width=15) (actual time=15.755..25905.866 rows=15 loops=1)
Index Cond: ((i.tree_sortkey >= l.tree_sortkey) AND (i.tree_sortkey <= tree_right(l.tree_sortkey)))
Filter: (acs_permission__permission_p(i.item_id, 0, 'write'::character varying) AND (subplan) AND (NOT (subplan)))
SubPlan
-> Nested Loop (cost=0.00..16.81 rows=1 width=0) (actual time=0.094..0.094 rows=0 loops=15)
Join Filter: ((j.tree_sortkey >= k.tree_sortkey) AND (j.tree_sortkey <= tree_right(k.tree_sortkey)))
-> Index Scan using cr_items_pk on cr_items j (cost=0.00..8.27 rows=1 width=11) (actual time=0.032..0.036 rows=1 loops=15)
Index Cond: ($0 = item_id)
Filter: (item_id <> 78948)
-> Index Scan using cr_items_pk on cr_items k (cost=0.00..8.27 rows=1 width=11) (actual time=0.020..0.025 rows=1 loops=15)
Index Cond: (k.item_id = 78948)
-> Seq Scan on cr_folders f (cost=0.00..1.34 rows=1 width=0) (actual time=0.074..0.074 rows=0 loops=5301)
Filter: (folder_id = $0)
SubPlan
-> Seq Scan on cr_folders f (cost=0.00..1.34 rows=1 width=4) (actual time=0.022..0.033 rows=1 loops=15)
Filter: (folder_id = $0)
-> Seq Scan on cr_folders f (cost=0.00..1.34 rows=1 width=9) (actual time=0.026..0.037 rows=1 loops=15)
Filter: (folder_id = $0)
Total runtime: 25913.827 ms
(25 rows)
The sequential scans look cheap; it seems to be the sorting that is the most expensive.
Any suggestions? Thanks in advance!