From b4df81e75a26c00f6b6830b15815eb20f6fd817a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 27 Jul 2017 15:03:12 +0200 Subject: [PATCH] Optimize queries used for fetching the service group summaries --- .../Backend/Ido/Query/ServicegroupQuery.php | 109 ++++++------- .../Ido/Query/ServicegroupsummaryQuery.php | 152 +++++------------- 2 files changed, 90 insertions(+), 171 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php index c0c49ca9a..ad23bc3ca 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupQuery.php @@ -5,64 +5,44 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query; class ServicegroupQuery extends IdoQuery { - /** - * {@inheritdoc} - */ + protected $groupBase = array( + 'servicegroups' => array('sgo.object_id, sg.servicegroup_id'), + 'servicestatus' => array('ss.servicestatus_id', 'hs.hoststatus_id') + ); + + protected $groupOrigin = array('members'); + protected $allowCustomVars = true; - /** - * {@inheritdoc} - */ - protected $groupBase = array('servicegroups' => array('sg.servicegroup_id', 'sgo.object_id')); - - /** - * {@inheritdoc} - */ - protected $groupOrigin = array('serviceobjects'); - - /** - * {@inheritdoc} - */ protected $columnMap = array( 'hostgroups' => array( - 'hostgroup' => 'hgo.name1 COLLATE latin1_general_ci', - 'hostgroup_alias' => 'hg.alias COLLATE latin1_general_ci', - 'hostgroup_name' => 'hgo.name1' - ), - 'hosts' => array( - 'host_alias' => 'h.alias', - 'host_display_name' => 'h.display_name COLLATE latin1_general_ci', + 'hostgroup_name' => 'hgo.name1' ), 'instances' => array( 'instance_name' => 'i.instance_name' ), + 'members' => array( + 'host_name' => 'so.name1', + 'service_description' => 'so.name2' + ), 'servicegroups' => array( - 'servicegroup' => 'sgo.name1 COLLATE latin1_general_ci', 'servicegroup_alias' => 'sg.alias COLLATE latin1_general_ci', 'servicegroup_name' => 'sgo.name1' ), - 'serviceobjects' => array( - 'host' => 'so.name1 COLLATE latin1_general_ci', - 'host_name' => 'so.name1', - 'service' => 'so.name2 COLLATE latin1_general_ci', - 'service_description' => 'so.name2' - ), - 'services' => array( - 'service_display_name' => 's.display_name COLLATE latin1_general_ci', + 'servicestatus' => array( + 'service_handled' => 'CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END', + 'service_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END' ) ); - /** - * {@inheritdoc} - */ protected function joinBaseTables() { $this->select->from( - array('sg' => $this->prefix . 'servicegroups'), + array('sgo' => $this->prefix . 'objects'), array() )->join( - array('sgo' => $this->prefix . 'objects'), - 'sg.servicegroup_object_id = sgo.object_id AND sgo.is_active = 1 AND sgo.objecttype_id = 4', + array('sg' => $this->prefix . 'servicegroups'), + 'sg.servicegroup_object_id = sgo.object_id AND sgo.objecttype_id = 4 AND sgo.is_active = 1', array() ); $this->joinedVirtualTables = array('servicegroups' => true); @@ -74,30 +54,17 @@ class ServicegroupQuery extends IdoQuery protected function joinHostgroups() { $this->requireVirtualTable('services'); - $this->select->joinLeft( + $this->select->join( array('hgm' => $this->prefix . 'hostgroup_members'), 'hgm.host_object_id = s.host_object_id', array() - )->joinLeft( + )->join( array('hg' => $this->prefix . 'hostgroups'), 'hg.hostgroup_id = hgm.hostgroup_id', array() - )->joinLeft( + )->join( array('hgo' => $this->prefix . 'objects'), - 'hgo.object_id = hg.hostgroup_object_id AND hgo.is_active = 1 AND hgo.objecttype_id = 3', - array() - ); - } - - /** - * Join hosts - */ - protected function joinHosts() - { - $this->requireVirtualTable('services'); - $this->select->joinLeft( - array('h' => $this->prefix . 'hosts'), - 'h.host_object_id = s.host_object_id', + 'hgo.object_id = hg.hostgroup_object_id AND hgo.objecttype_id = 3 AND hgo.is_active = 1', array() ); } @@ -117,15 +84,15 @@ class ServicegroupQuery extends IdoQuery /** * Join service objects */ - protected function joinServiceobjects() + protected function joinMembers() { - $this->select->joinLeft( + $this->select->join( array('sgm' => $this->prefix . 'servicegroup_members'), - 'sgm.' . $this->servicegroup_id . ' = sg.' . $this->servicegroup_id, + 'sgm.servicegroup_id = sg.servicegroup_id', array() - )->joinLeft( + )->join( array('so' => $this->prefix . 'objects'), - 'sgm.service_object_id = so.object_id', + 'so.object_id = sgm.service_object_id AND so.objecttype_id = 2 AND so.is_active = 1', array() ); } @@ -135,11 +102,29 @@ class ServicegroupQuery extends IdoQuery */ protected function joinServices() { - $this->requireVirtualTable('serviceobjects'); - $this->select->joinLeft( + $this->requireVirtualTable('members'); + $this->select->join( array('s' => $this->prefix . 'services'), 's.service_object_id = so.object_id', array() ); } + + /** + * Join service status + */ + protected function joinServicestatus() + { + $this->requireVirtualTable('services'); + $this->select->join( + array('hs' => $this->prefix . 'hoststatus'), + 'hs.host_object_id = s.host_object_id', + array() + ); + $this->select->join( + array('ss' => $this->prefix . 'servicestatus'), + 'ss.service_object_id = so.object_id', + array() + ); + } } diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupsummaryQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupsummaryQuery.php index a99728b81..e34f8e38e 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupsummaryQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicegroupsummaryQuery.php @@ -4,149 +4,83 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query; use Icinga\Data\Filter\Filter; -use Zend_Db_Expr; -use Zend_Db_Select; /** * Query for service group summary */ class ServicegroupsummaryQuery extends IdoQuery { - /** - * {@inheritdoc} - */ + + protected $allowCustomVars = true; + protected $columnMap = array( - 'servicestatussummary' => array( - 'servicegroup' => 'servicegroup COLLATE latin1_general_ci', - 'servicegroup_alias' => 'servicegroup_alias COLLATE latin1_general_ci', + 'servicegroupsummary' => array( + 'servicegroup_alias' => 'servicegroup_alias', 'servicegroup_name' => 'servicegroup_name', - 'services_critical' => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 THEN 1 ELSE 0 END)', - 'services_critical_handled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND handled + host_state > 0 THEN 1 ELSE 0 END)', - 'services_critical_handled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 2 AND handled + host_state > 0 THEN state_change ELSE 0 END)', - 'services_critical_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND handled + host_state = 0 THEN 1 ELSE 0 END)', - 'services_critical_unhandled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 2 AND handled + host_state = 0 THEN state_change ELSE 0 END)', - 'services_ok' => 'SUM(CASE WHEN object_type = \'service\' AND state = 0 THEN 1 ELSE 0 END)', - 'services_ok_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 0 THEN state_change ELSE 0 END)', - 'services_pending' => 'SUM(CASE WHEN object_type = \'service\' AND state = 99 THEN 1 ELSE 0 END)', - 'services_pending_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 99 THEN state_change ELSE 0 END)', - 'services_severity' => 'MAX(CASE WHEN object_type = \'service\' THEN severity ELSE 0 END)', - 'services_total' => 'SUM(CASE WHEN object_type = \'service\' THEN 1 ELSE 0 END)', - 'services_unknown' => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 THEN 1 ELSE 0 END)', - 'services_unknown_handled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND handled + host_state > 0 THEN 1 ELSE 0 END)', - 'services_unknown_handled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 3 AND handled + host_state > 0 THEN state_change ELSE 0 END)', - 'services_unknown_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND handled + host_state = 0 THEN 1 ELSE 0 END)', - 'services_unknown_unhandled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 3 AND handled + host_state = 0 THEN state_change ELSE 0 END)', - 'services_warning' => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 THEN 1 ELSE 0 END)', - 'services_warning_handled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND handled + host_state > 0 THEN 1 ELSE 0 END)', - 'services_warning_handled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 1 AND handled + host_state > 0 THEN state_change ELSE 0 END)', - 'services_warning_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND handled + host_state = 0 THEN 1 ELSE 0 END)', - 'services_warning_unhandled_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 1 AND handled + host_state = 0 THEN state_change ELSE 0 END)' + 'services_critical' => 'SUM(CASE WHEN service_state = 2 THEN 1 ELSE 0 END)', + 'services_critical_handled' => 'SUM(CASE WHEN service_state = 2 AND service_handled = 1 THEN 1 ELSE 0 END)', + 'services_critical_unhandled' => 'SUM(CASE WHEN service_state = 2 AND service_handled = 0 THEN 1 ELSE 0 END)', + 'services_ok' => 'SUM(CASE WHEN service_state = 0 THEN 1 ELSE 0 END)', + 'services_pending' => 'SUM(CASE WHEN service_state = 99 THEN 1 ELSE 0 END)', + 'services_total' => 'SUM(1)', + 'services_unknown' => 'SUM(CASE WHEN service_state = 3 THEN 1 ELSE 0 END)', + 'services_unknown_handled' => 'SUM(CASE WHEN service_state = 3 AND service_handled = 1 THEN 1 ELSE 0 END)', + 'services_unknown_unhandled' => 'SUM(CASE WHEN service_state = 3 AND service_handled = 0 THEN 1 ELSE 0 END)', + 'services_warning' => 'SUM(CASE WHEN service_state = 1 THEN 1 ELSE 0 END)', + 'services_warning_handled' => 'SUM(CASE WHEN service_state = 1 AND service_handled = 1 THEN 1 ELSE 0 END)', + 'services_warning_unhandled' => 'SUM(CASE WHEN service_state = 1 AND service_handled = 0 THEN 1 ELSE 0 END)', ) ); /** - * The union + * Subquery used for the summary query * - * @var Zend_Db_Select + * @var IdoQuery */ - protected $summaryQuery; + protected $subQuery; /** - * Subqueries used for the summary query + * Count query * - * @var IdoQuery[] + * @var IdoQuery */ - protected $subQueries = array(); + protected $countQuery; - /** - * {@inheritdoc} - */ - public function allowsCustomVars() - { - foreach ($this->subQueries as $query) { - if (! $query->allowsCustomVars()) { - return false; - } - } - - return true; - } - - /** - * {@inheritdoc} - */ public function addFilter(Filter $filter) { - foreach ($this->subQueries as $sub) { - $sub->applyFilter(clone $filter); - } + $this->subQuery->applyFilter(clone $filter); + $this->countQuery->applyFilter(clone $filter); return $this; } - /** - * {@inheritdoc} - */ protected function joinBaseTables() { - // TODO(el): Allow to switch between hard and soft states - $hosts = $this->createSubQuery( - 'Hoststatus', + $this->countQuery = $this->createSubQuery( + 'Servicegroup', + array() + ); + $subQuery = $this->createSubQuery( + 'Servicegroup', array( - 'handled' => 'host_handled', - 'host_state' => new Zend_Db_Expr('NULL'), 'servicegroup_alias', 'servicegroup_name', - 'object_type', - 'severity' => new Zend_Db_Expr('NULL'), - 'state' => 'host_state', - 'state_change' => 'host_last_state_change' + 'service_handled', + 'service_state' ) ); - $hosts->select()->where('sgo.name1 IS NOT NULL'); // TODO(9458): Should be possible using our filters! - $this->subQueries[] = $hosts; - $services = $this->createSubQuery( - 'Servicestatus', - array( - 'handled' => 'service_handled', - 'host_state' => 'host_state', - 'servicegroup_alias', - 'servicegroup_name', - 'object_type', - 'severity' => 'service_severity', - 'state' => 'service_state', - 'state_change' => 'service_last_state_change' - ) - ); - $services->select()->where('sgo.name1 IS NOT NULL'); // TODO(9458): Should be possible using our filters! - $this->subQueries[] = $services; - $this->summaryQuery = $this->db->select()->union(array($hosts, $services), Zend_Db_Select::SQL_UNION_ALL); - $this->select->from(array('statussummary' => $this->summaryQuery), array()); + $subQuery->setIsSubQuery(); + $this->subQuery = $subQuery; + $this->select->from(array('servicesgroupsummary' => $this->subQuery), array()); $this->group(array('servicegroup_name', 'servicegroup_alias')); - $this->joinedVirtualTables['servicestatussummary'] = true; + $this->joinedVirtualTables['servicegroupsummary'] = true; } - /** - * {@inheritdoc} - */ - public function order($columnOrAlias, $dir = null) + public function getCountQuery() { - if (! $this->hasAliasName($columnOrAlias)) { - foreach ($this->subQueries as $sub) { - $sub->requireColumn($columnOrAlias); - } - } - return parent::order($columnOrAlias, $dir); - } - - /** - * {@inheritdoc} - */ - public function where($condition, $value = null) - { - $this->requireColumn($condition); - foreach ($this->subQueries as $sub) { - $sub->where($condition, $value); - } - return $this; + $count = $this->countQuery->select(); + $this->countQuery->applyFilterSql($count); + $count->columns(array('sgo.object_id')); + $count->group(array('sgo.object_id')); + return $this->db->select()->from($count, array('cnt' => 'COUNT(*)')); } }