From 876649fe6fa596d90b417a12d39875ab2b05ecb3 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sun, 19 Oct 2008 11:34:12 +0000 Subject: [PATCH] Big performance improvment by: - using egw_link::set_cache() for entries read or searched --> eliminates an excessive number of single entry reads, when the links need titles or file_access permissions - removing sub-query for number of sub-entries from search (Bug #1613) - method to query the number of sub-entries of all displayed entries in one go --- infolog/inc/class.infolog_bo.inc.php | 43 +++++++++++++++++------ infolog/inc/class.infolog_so.inc.php | 51 ++++++++++++---------------- infolog/inc/class.infolog_ui.inc.php | 4 ++- 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php index bafb2fc34b..9b2f7cdaac 100644 --- a/infolog/inc/class.infolog_bo.inc.php +++ b/infolog/inc/class.infolog_bo.inc.php @@ -415,6 +415,9 @@ class infolog_bo { if ($data[$time]) $data[$time] += $this->tz_offset_s; } + // pre-cache title and file access + self::set_link_cache($data); + return $data; } @@ -654,6 +657,9 @@ class infolog_bo // notify the link-class about the update, as other apps may be subscribt to it egw_link::notify_update('infolog',$info_id,$values); + // pre-cache the new values + self::set_link_cache($values); + // send email notifications and do the history logging if (!is_object($this->tracking)) { @@ -667,10 +673,10 @@ class infolog_bo } /** - * Query the number of children / subs + * Query the number of children / subs for one or more info_id's * - * @param int $info_id id - * @return int number of subs + * @param int|array $info_id id + * @return int|array number of subs */ function anzSubs( $info_id ) { @@ -696,21 +702,25 @@ class infolog_bo $ret = $this->so->search($query); // convert system- to user-time - if (is_array($ret) && $this->tz_offset_s) + if (is_array($ret)) { - foreach($ret as $id => $data) + foreach($ret as $id => &$data) { - foreach($this->timestamps as $time) + if($this->tz_offset_s) { - if ($data[$time]) $ret[$id][$time] += $this->tz_offset_s; + foreach($this->timestamps as $time) + { + if ($data[$time]) $data[$time] += $this->tz_offset_s; + } } + // pre-cache title and file access + self::set_link_cache($data); } } //echo "

boinfolog::search(".print_r($query,True).")=

".print_r($ret,True)."
\n"; return $ret; } - /** * imports a mail identified by uid as infolog * @@ -868,15 +878,28 @@ class infolog_bo /** * Check access to the projects file store * - * @param int $id id of entry + * @param int|array $id id of entry or entry array * @param int $check EGW_ACL_READ for read and EGW_ACL_EDIT for write or delete access * @return boolean true if access is granted or false otherwise */ - function file_access($id,$check,$rel_path) + function file_access($id,$check,$rel_path=null) { return $this->check_access($id,$check); } + /** + * Set the cache of the link class (title, file_access) for the given infolog entry + * + * @param array $info + */ + function set_link_cache(array $info) + { + egw_link::set_cache('infolog',$info['info_id'], + $this->link_title($info), + $this->file_access($info,EGW_ACL_EDIT) ? EGW_ACL_READ|EGW_ACL_EDIT : + ($this->file_access($info,EGW_ACL_READ) ? EGW_ACL_READ : 0)); + } + /** * hook called be calendar to include events or todos in the cal-dayview * diff --git a/infolog/inc/class.infolog_so.inc.php b/infolog/inc/class.infolog_so.inc.php index f0bc12241a..2bf11ea71f 100644 --- a/infolog/inc/class.infolog_so.inc.php +++ b/infolog/inc/class.infolog_so.inc.php @@ -15,13 +15,8 @@ * * all values passed to this class are run either through intval or addslashes to prevent query-insertion * and for pgSql 7.3 compatibility - * - * @package infolog - * @author Ralf Becker - * @copyright (c) by Ralf Becker - * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License */ -class infolog_so // DB-Layer +class infolog_so { /** * Instance of the db class @@ -213,9 +208,10 @@ class infolog_so // DB-Layer } if (count($private_user_list)) { - $has_private_access = 'info_owner IN ('.implode(',',$private_user_list).')'; + $has_private_access = $this->db->expression($this->info_table,array('info_owner' => $private_user_list)); } } + $public_access = $this->db->expression($this->info_table,array('info_owner' => $public_user_list)); // implicit read-rights for responsible user $filtermethod .= " OR (".$this->responsible_filter($this->user)." AND info_access='public')"; @@ -224,7 +220,7 @@ class infolog_so // DB-Layer { $filtermethod .= " OR (".$this->responsible_filter($this->user). ($filter == 'own' && count($public_user_list) ? // offer's should show up in own, eg. startpage, but need read-access - " OR info_status = 'offer' AND info_owner IN(" . implode(',',$public_user_list) . ')' : '').")". + " OR info_status = 'offer' AND $public_access" : '').")". " AND (info_access='public'".($has_private_access?" OR $has_private_access":'').')'; } elseif ($filter != 'my' && $filter != 'responsible') // none --> all entrys user has rights to see @@ -235,7 +231,7 @@ class infolog_so // DB-Layer } if (count($public_user_list)) { - $filtermethod .= " OR (info_access='public' AND info_owner IN(" . implode(',',$public_user_list) . '))'; + $filtermethod .= " OR (info_access='public' AND $public_access)"; } } $filtermethod .= ') '; @@ -348,6 +344,7 @@ class infolog_so // DB-Layer */ function read($info_id) // did _not_ ensure ACL { + //echo "

read($info_id) ".function_backtrace()."

\n"; if ($info_id && ((int)$info_id == $this->data['info_id'] || $info_id == $this->data['info_uid'])) { return $this->data; // return the already read entry @@ -587,30 +584,28 @@ class infolog_so // DB-Layer * * This is done now be search too (in key info_anz_subs), if DB can use sub-queries * - * @param $info_id id of log-entry - * @return int the number of sub-entries + * @param int|array $info_id id(s) of log-entry + * @return int|array the number of sub-entries or indexed by info_id, if array as param given */ function anzSubs( $info_id ) { - if (($info_id = intval($info_id)) <= 0) + if (!is_array($info_id) || !$info_id) { - return 0; + if ((int)$info_id <= 0) return 0; } - $this->db->select($this->info_table,'count(*)',array( - 'info_id_parent' => $info_id, - $this->aclFilter() - ),__LINE__,__FILE__); - - $this->db->next_record(); - //echo "

anzSubs($info_id) = ".$this->db->f(0)." ($sql)

\n"; - return $this->db->f(0); + $counts = array(); + foreach($this->db->select($this->info_table,'info_id_parent,COUNT(*) AS info_anz_subs',array('info_id_parent' => $info_id),__LINE__,__FILE__, + false,'GROUP BY info_id_parent','infolog') as $row) + { + $counts[$row['info_id_parent']] = (int)$row['info_anz_subs']; + } + //echo '

'.__METHOD__."($info_id) = ".array2string($counts)."

\n"; + return is_array($info_id) ? $counts : (int)array_pop($counts); } /** * searches InfoLog for a certain pattern in $query * - * If DB can use sub-queries, the number of subs are under the key info_anz_subs. - * * @param $query[order] column-name to sort after * @param $query[sort] sort-order DESC or ASC * @param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or '' @@ -716,7 +711,7 @@ class infolog_so // DB-Layer $cats = $GLOBALS['egw']->categories->return_all_children((int)$query['cat_id']); $filtermethod .= ' AND info_cat'.(count($cats)>1? ' IN ('.implode(',',$cats).') ' : '='.(int)$query['cat_id']); } - $join = $distinct = $count_subs = ''; + $join = $distinct = ''; if ($query['query']) $query['search'] = $query['query']; // allow both names if ($query['search']) // we search in _from, _subject, _des and _extra_value for $query { @@ -771,23 +766,19 @@ class infolog_so // DB-Layer { $query['total'] = $this->db->query($sql="SELECT $distinct main.info_id ".$sql_query,__LINE__,__FILE__)->NumRows(); } - if ($this->db->capabilities['sub_queries']) - { - $count_subs = ",(SELECT COUNT(*) FROM $this->info_table sub WHERE sub.info_id_parent=main.info_id AND $acl_filter) AS info_anz_subs"; - } $info_customfield = ''; if ($sortbycf != '') { $info_customfield = ", (SELECT DISTINCT info_extra_value FROM $this->extra_table sub2 where sub2.info_id=main.info_id AND info_extra_name=".$this->db->quote($sortbycf).") AS cfsortcrit "; } - //echo "SELECT $distinct main.* $count_subs $info_customfield $sql_query $ordermethod"."
"; + //echo "SELECT $distinct main.* $info_customfield $sql_query $ordermethod"."
"; do { if (isset($query['start']) && isset($query['total']) && $query['start'] > $query['total']) { $query['start'] = 0; } - $rs = $this->db->query($sql="SELECT $mysql_calc_rows $distinct main.* $count_subs $info_customfield $sql_query $ordermethod",__LINE__,__FILE__, + $rs = $this->db->query($sql="SELECT $mysql_calc_rows $distinct main.* $info_customfield $sql_query $ordermethod",__LINE__,__FILE__, (int) $query['start'],isset($query['start']) ? (int) $query['num_rows'] : -1,false,egw_db::FETCH_ASSOC); //echo "

db::query('$sql',,,".(int)$query['start'].','.(isset($query['start']) ? (int) $query['num_rows'] : -1).")

\n"; diff --git a/infolog/inc/class.infolog_ui.inc.php b/infolog/inc/class.infolog_ui.inc.php index 593f11f35c..954415a11f 100644 --- a/infolog/inc/class.infolog_ui.inc.php +++ b/infolog/inc/class.infolog_ui.inc.php @@ -355,10 +355,11 @@ class infolog_ui // set old show_times pref, that get_info calculates the cumulated time of the timesheets $this->prefs['show_times'] = strpos($this->prefs['nextmatch-'.$query['columnselection_pref']],'info_used_time_info_planned_time_info_replanned_time') !== false; - // query all links in one go + // query all links and sub counts in one go if ($infos && !$query['csv_export']) { $links = bolink::get_links_multiple('infolog',array_keys($infos)); + $anzSubs = $this->bo->anzSubs(array_keys($infos)); } $readonlys = $rows = array(); foreach($infos as $id => $info) @@ -366,6 +367,7 @@ class infolog_ui if (!$query['csv_export']) { $info['links'] =& $links[$id]; + $info['info_anz_subs'] = (int)$anzSubs[$id]; $info = $this->get_info($info,$readonlys,$query['action'],$query['action_id'],$query['filter2'],$details); if (!$query['filter2'] && $this->prefs['show_links'] == 'no_describtion' ||