Skip to content

Commit 88de091

Browse files
orthaghtrashercedric-anne
authored
a few optimizations for dashboards (#21988)
* a few sql optimization for dashboards * improve reporting of debug card times * extends to all concerned itemtype * fix * fix sql * fix sql * miss a comma * cache appliable filters * is_deleted key is included in active_assets key * another costy distinct * another bunch of superflu is_deleted * add ttl for cache * comment * differentiate cache for filter by user id * fix count distinct * Apply suggestions from code review Co-authored-by: Johan Cwiklinski <[email protected]> * Apply suggestions from code review Co-authored-by: Cédric Anne <[email protected]> * bad variable --------- Co-authored-by: Johan Cwiklinski <[email protected]> Co-authored-by: Cédric Anne <[email protected]>
1 parent f1d7635 commit 88de091

File tree

5 files changed

+127
-29
lines changed

5 files changed

+127
-29
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/**
4+
* ---------------------------------------------------------------------
5+
*
6+
* GLPI - Gestionnaire Libre de Parc Informatique
7+
*
8+
* http://glpi-project.org
9+
*
10+
* @copyright 2015-2025 Teclib' and contributors.
11+
* @licence https://www.gnu.org/licenses/gpl-3.0.html
12+
*
13+
* ---------------------------------------------------------------------
14+
*
15+
* LICENSE
16+
*
17+
* This file is part of GLPI.
18+
*
19+
* This program is free software: you can redistribute it and/or modify
20+
* it under the terms of the GNU General Public License as published by
21+
* the Free Software Foundation, either version 3 of the License, or
22+
* (at your option) any later version.
23+
*
24+
* This program is distributed in the hope that it will be useful,
25+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
26+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+
* GNU General Public License for more details.
28+
*
29+
* You should have received a copy of the GNU General Public License
30+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
31+
*
32+
* ---------------------------------------------------------------------
33+
*/
34+
/**
35+
* @var Migration $migration
36+
*/
37+
38+
$assets_tables_with_templates_and_trashbin = [
39+
'glpi_budgets',
40+
'glpi_certificates',
41+
'glpi_computers',
42+
'glpi_contracts',
43+
'glpi_domains',
44+
'glpi_cables',
45+
'glpi_monitors',
46+
'glpi_networkequipments',
47+
'glpi_passivedcequipments',
48+
'glpi_peripherals',
49+
'glpi_phones',
50+
'glpi_printers',
51+
'glpi_projects',
52+
'glpi_projecttasks',
53+
'glpi_softwarelicenses',
54+
'glpi_softwares',
55+
'glpi_racks',
56+
'glpi_enclosures',
57+
'glpi_pdus',
58+
'glpi_assets_assets',
59+
];
60+
61+
foreach ($assets_tables_with_templates_and_trashbin as $table) {
62+
$migration->addKey($table, ['is_deleted', 'is_template'], 'active_assets');
63+
$migration->dropKey($table, 'is_deleted');
64+
}

install/mysql/glpi-empty.sql

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,10 @@ CREATE TABLE `glpi_budgets` (
316316
KEY `name` (`name`),
317317
KEY `is_recursive` (`is_recursive`),
318318
KEY `entities_id` (`entities_id`),
319-
KEY `is_deleted` (`is_deleted`),
320319
KEY `begin_date` (`begin_date`),
321320
KEY `end_date` (`end_date`),
322321
KEY `is_template` (`is_template`),
322+
KEY `active_assets` (`is_deleted`, `is_template`),
323323
KEY `date_mod` (`date_mod`),
324324
KEY `date_creation` (`date_creation`),
325325
KEY `locations_id` (`locations_id`),
@@ -560,7 +560,7 @@ CREATE TABLE `glpi_certificates` (
560560
KEY `entities_id` (`entities_id`),
561561
KEY `is_recursive` (`is_recursive`),
562562
KEY `is_template` (`is_template`),
563-
KEY `is_deleted` (`is_deleted`),
563+
KEY `active_assets` (`is_deleted`, `is_template`),
564564
KEY `certificatetypes_id` (`certificatetypes_id`),
565565
KEY `users_id_tech` (`users_id_tech`),
566566
KEY `users_id` (`users_id`),
@@ -1009,7 +1009,7 @@ CREATE TABLE `glpi_computers` (
10091009
KEY `states_id` (`states_id`),
10101010
KEY `users_id_tech` (`users_id_tech`),
10111011
KEY `computertypes_id` (`computertypes_id`),
1012-
KEY `is_deleted` (`is_deleted`),
1012+
KEY `active_assets` (`is_deleted`, `is_template`),
10131013
KEY `is_dynamic` (`is_dynamic`),
10141014
KEY `serial` (`serial`),
10151015
KEY `otherserial` (`otherserial`),
@@ -1519,8 +1519,8 @@ CREATE TABLE `glpi_contracts` (
15191519
KEY `locations_id` (`locations_id`),
15201520
KEY `entities_id` (`entities_id`),
15211521
KEY `is_recursive` (`is_recursive`),
1522-
KEY `is_deleted` (`is_deleted`),
15231522
KEY `is_template` (`is_template`),
1523+
KEY `active_assets` (`is_deleted`, `is_template`),
15241524
KEY `use_sunday` (`use_sunday`),
15251525
KEY `use_saturday` (`use_saturday`),
15261526
KEY `alert` (`alert`),
@@ -2694,8 +2694,8 @@ CREATE TABLE `glpi_domains` (
26942694
KEY `users_id` (`users_id`),
26952695
KEY `users_id_tech` (`users_id_tech`),
26962696
KEY `date_mod` (`date_mod`),
2697-
KEY `is_deleted` (`is_deleted`),
26982697
KEY `is_template` (`is_template`),
2698+
KEY `active_assets` (`is_deleted`, `is_template`),
26992699
KEY `is_active` (`is_active`),
27002700
KEY `date_expiration` (`date_expiration`),
27012701
KEY `date_domaincreation` (`date_domaincreation`),
@@ -4443,7 +4443,7 @@ CREATE TABLE `glpi_monitors` (
44434443
KEY `states_id` (`states_id`),
44444444
KEY `users_id_tech` (`users_id_tech`),
44454445
KEY `monitortypes_id` (`monitortypes_id`),
4446-
KEY `is_deleted` (`is_deleted`),
4446+
KEY `active_assets` (`is_deleted`, `is_template`),
44474447
KEY `is_dynamic` (`is_dynamic`),
44484448
KEY `autoupdatesystems_id` (`autoupdatesystems_id`),
44494449
KEY `serial` (`serial`),
@@ -4548,7 +4548,7 @@ CREATE TABLE `glpi_cables` (
45484548
KEY `cabletypes_id` (`cabletypes_id`),
45494549
KEY `date_mod` (`date_mod`),
45504550
KEY `date_creation` (`date_creation`),
4551-
KEY `is_deleted` (`is_deleted`)
4551+
KEY `active_assets` (`is_deleted`, `is_template`)
45524552
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
45534553

45544554

@@ -4693,7 +4693,7 @@ CREATE TABLE `glpi_networkequipments` (
46934693
KEY `states_id` (`states_id`),
46944694
KEY `users_id_tech` (`users_id_tech`),
46954695
KEY `networkequipmenttypes_id` (`networkequipmenttypes_id`),
4696-
KEY `is_deleted` (`is_deleted`),
4696+
KEY `active_assets` (`is_deleted`, `is_template`),
46974697
KEY `date_mod` (`date_mod`),
46984698
KEY `is_dynamic` (`is_dynamic`),
46994699
KEY `serial` (`serial`),
@@ -5247,7 +5247,7 @@ CREATE TABLE `glpi_passivedcequipments` (
52475247
KEY `users_id` (`users_id`),
52485248
KEY `users_id_tech` (`users_id_tech`),
52495249
KEY `is_template` (`is_template`),
5250-
KEY `is_deleted` (`is_deleted`),
5250+
KEY `active_assets` (`is_deleted`, `is_template`),
52515251
KEY `states_id` (`states_id`),
52525252
KEY `manufacturers_id` (`manufacturers_id`),
52535253
KEY `date_creation` (`date_creation`),
@@ -5368,7 +5368,7 @@ CREATE TABLE `glpi_peripherals` (
53685368
KEY `states_id` (`states_id`),
53695369
KEY `users_id_tech` (`users_id_tech`),
53705370
KEY `peripheraltypes_id` (`peripheraltypes_id`),
5371-
KEY `is_deleted` (`is_deleted`),
5371+
KEY `active_assets` (`is_deleted`, `is_template`),
53725372
KEY `date_mod` (`date_mod`),
53735373
KEY `is_dynamic` (`is_dynamic`),
53745374
KEY `autoupdatesystems_id` (`autoupdatesystems_id`),
@@ -5482,7 +5482,7 @@ CREATE TABLE `glpi_phones` (
54825482
KEY `states_id` (`states_id`),
54835483
KEY `users_id_tech` (`users_id_tech`),
54845484
KEY `phonetypes_id` (`phonetypes_id`),
5485-
KEY `is_deleted` (`is_deleted`),
5485+
KEY `active_assets` (`is_deleted`, `is_template`),
54865486
KEY `date_mod` (`date_mod`),
54875487
KEY `is_dynamic` (`is_dynamic`),
54885488
KEY `autoupdatesystems_id` (`autoupdatesystems_id`),
@@ -5624,7 +5624,7 @@ CREATE TABLE `glpi_printers` (
56245624
KEY `states_id` (`states_id`),
56255625
KEY `users_id_tech` (`users_id_tech`),
56265626
KEY `printertypes_id` (`printertypes_id`),
5627-
KEY `is_deleted` (`is_deleted`),
5627+
KEY `active_assets` (`is_deleted`, `is_template`),
56285628
KEY `date_mod` (`date_mod`),
56295629
KEY `last_pages_counter` (`last_pages_counter`),
56305630
KEY `is_dynamic` (`is_dynamic`),
@@ -5990,7 +5990,6 @@ CREATE TABLE `glpi_projects` (
59905990
KEY `code` (`code`),
59915991
KEY `entities_id` (`entities_id`),
59925992
KEY `is_recursive` (`is_recursive`),
5993-
KEY `is_deleted` (`is_deleted`),
59945993
KEY `projects_id` (`projects_id`),
59955994
KEY `projectstates_id` (`projectstates_id`),
59965995
KEY `projecttypes_id` (`projecttypes_id`),
@@ -6007,7 +6006,8 @@ CREATE TABLE `glpi_projects` (
60076006
KEY `show_on_global_gantt` (`show_on_global_gantt`),
60086007
KEY `date_creation` (`date_creation`),
60096008
KEY `projecttemplates_id` (`projecttemplates_id`),
6010-
KEY `is_template` (`is_template`)
6009+
KEY `is_template` (`is_template`),
6010+
KEY `active_assets` (`is_deleted`, `is_template`)
60116011
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
60126012

60136013

@@ -6069,7 +6069,6 @@ CREATE TABLE `glpi_projecttasks` (
60696069
KEY `is_recursive` (`is_recursive`),
60706070
KEY `projects_id` (`projects_id`),
60716071
KEY `projecttasks_id` (`projecttasks_id`),
6072-
KEY `is_deleted` (`is_deleted`),
60736072
KEY `date_creation` (`date_creation`),
60746073
KEY `date_mod` (`date_mod`),
60756074
KEY `users_id` (`users_id`),
@@ -6082,6 +6081,7 @@ CREATE TABLE `glpi_projecttasks` (
60826081
KEY `projecttasktypes_id` (`projecttasktypes_id`),
60836082
KEY `projecttasktemplates_id` (`projecttasktemplates_id`),
60846083
KEY `is_template` (`is_template`),
6084+
KEY `active_assets` (`is_deleted`, `is_template`),
60856085
KEY `is_milestone` (`is_milestone`)
60866086
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
60876087

@@ -6811,7 +6811,7 @@ CREATE TABLE `glpi_softwarelicenses` (
68116811
KEY `users_id_tech` (`users_id_tech`),
68126812
KEY `users_id` (`users_id`),
68136813
KEY `is_helpdesk_visible` (`is_helpdesk_visible`),
6814-
KEY `is_deleted` (`is_deleted`),
6814+
KEY `active_assets` (`is_deleted`, `is_template`),
68156815
KEY `date_creation` (`date_creation`),
68166816
KEY `manufacturers_id` (`manufacturers_id`),
68176817
KEY `states_id` (`states_id`),
@@ -6886,9 +6886,9 @@ CREATE TABLE `glpi_softwares` (
68866886
KEY `locations_id` (`locations_id`),
68876887
KEY `users_id_tech` (`users_id_tech`),
68886888
KEY `softwares_id` (`softwares_id`),
6889-
KEY `is_deleted` (`is_deleted`),
68906889
KEY `is_helpdesk_visible` (`is_helpdesk_visible`),
6891-
KEY `date_creation` (`date_creation`)
6890+
KEY `date_creation` (`date_creation`),
6891+
KEY `active_assets` (`is_deleted`,`is_template`)
68926892
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
68936893

68946894

@@ -8388,7 +8388,7 @@ CREATE TABLE `glpi_racks` (
83888388
KEY `users_id` (`users_id`),
83898389
KEY `users_id_tech` (`users_id_tech`),
83908390
KEY `is_template` (`is_template`),
8391-
KEY `is_deleted` (`is_deleted`),
8391+
KEY `active_assets` (`is_deleted`, `is_template`),
83928392
KEY `dcrooms_id` (`dcrooms_id`),
83938393
KEY `date_creation` (`date_creation`),
83948394
KEY `date_mod` (`date_mod`)
@@ -8465,7 +8465,7 @@ CREATE TABLE `glpi_enclosures` (
84658465
KEY `users_id` (`users_id`),
84668466
KEY `users_id_tech` (`users_id_tech`),
84678467
KEY `is_template` (`is_template`),
8468-
KEY `is_deleted` (`is_deleted`),
8468+
KEY `active_assets` (`is_deleted`, `is_template`),
84698469
KEY `states_id` (`states_id`),
84708470
KEY `manufacturers_id` (`manufacturers_id`),
84718471
KEY `date_mod` (`date_mod`),
@@ -8558,7 +8558,7 @@ CREATE TABLE `glpi_pdus` (
85588558
KEY `users_id` (`users_id`),
85598559
KEY `users_id_tech` (`users_id_tech`),
85608560
KEY `is_template` (`is_template`),
8561-
KEY `is_deleted` (`is_deleted`),
8561+
KEY `active_assets` (`is_deleted`, `is_template`),
85628562
KEY `states_id` (`states_id`),
85638563
KEY `manufacturers_id` (`manufacturers_id`),
85648564
KEY `pdutypes_id` (`pdutypes_id`),
@@ -10044,7 +10044,7 @@ CREATE TABLE `glpi_assets_assets` (
1004410044
KEY `states_id` (`states_id`),
1004510045
KEY `entities_id` (`entities_id`),
1004610046
KEY `is_recursive` (`is_recursive`),
10047-
KEY `is_deleted` (`is_deleted`),
10047+
KEY `active_assets` (`is_deleted`, `is_template`),
1004810048
KEY `is_template` (`is_template`),
1004910049
KEY `is_dynamic` (`is_dynamic`),
1005010050
KEY `autoupdatesystems_id` (`autoupdatesystems_id`),

src/Glpi/Dashboard/Filter.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ class Filter extends CommonDBChild
6969
*/
7070
public static function getAppliableFilters(string $table): array
7171
{
72+
global $GLPI_CACHE;
73+
74+
$cache_key = "dashboard_filters_appliable_$table" . Session::getLoginUserID();
75+
if (($filters_ids = $GLPI_CACHE->get($cache_key)) !== null) {
76+
return $filters_ids;
77+
}
78+
7279
$filters_ids = [];
7380

7481
foreach (self::getRegisteredFilterClasses() as $filter_class) {
@@ -77,6 +84,11 @@ public static function getAppliableFilters(string $table): array
7784
}
7885
}
7986

87+
// Set a short cache to have an auto-invalidation;
88+
// 5s should be enough to load a full dashboard
89+
// and expiring before the user hit another request.
90+
$GLPI_CACHE->set($cache_key, $filters_ids, 5);
91+
8092
return $filters_ids;
8193
}
8294

src/Glpi/Dashboard/Grid.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,8 @@ public function getCardHtml(string $card_id = "", array $card_options = []): str
978978
{
979979
global $GLPI_CACHE;
980980

981+
$start = microtime(true);
982+
981983
$force = ($card_options['args']['force'] ?? $card_options['force'] ?? false);
982984

983985
// retrieve card
@@ -1086,9 +1088,10 @@ public function getCardHtml(string $card_id = "", array $card_options = []): str
10861088
Profiler::getInstance()->stop(__METHOD__ . ' get card data');
10871089

10881090
if ($_SESSION['glpi_use_mode'] === Session::DEBUG_MODE) {
1089-
// Use the current PHP request duration as the execution time for a more accurate card loading time
1090-
$execution_time = Profiler::getInstance()->getCurrentDuration('php_request');
1091-
$html .= '<span class="debug-card">' . \htmlescape($execution_time) . 'ms</span>';
1091+
$html .= '<span class="debug-card">';
1092+
$html .= "total: " . \htmlescape(Profiler::getInstance()->getCurrentDuration('php_request')) . 'ms - ';
1093+
$html .= "card: " . \htmlescape(round((microtime(true) - $start) * 1000)) . 'ms';
1094+
$html .= '</span>';
10921095
}
10931096

10941097
return $html;

src/Glpi/Dashboard/Provider.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,11 @@ public static function bigNumberItem(?CommonDBTM $item = null, array $params = [
130130
$where += getEntitiesRestrictCriteria($item::getTable(), '', '', $item->maybeRecursive());
131131
}
132132
$request = [
133-
'SELECT' => ['COUNT DISTINCT' => $item::getTableField($item::getIndexName()) . ' as cpt'],
134-
'FROM' => $i_table,
135-
'WHERE' => $where,
133+
'SELECT' => $item::getTableField($item::getIndexName()),
134+
'COUNT' => 'cpt',
135+
'DISTINCT' => true,
136+
'FROM' => $i_table,
137+
'WHERE' => $where,
136138
];
137139
}
138140

@@ -141,6 +143,15 @@ public static function bigNumberItem(?CommonDBTM $item = null, array $params = [
141143
self::getFiltersCriteria($i_table, $params['apply_filters']),
142144
$item instanceof Ticket ? Ticket::getCriteriaFromProfile() : []
143145
);
146+
147+
// avoid costly DISTINCT if there isn't any JOIN (/3 perf gain)
148+
if (!isset($criteria['LEFT JOIN'])
149+
&& !isset($criteria['JOIN'])
150+
&& !isset($criteria['INNER JOIN'])
151+
&& !isset($criteria['RIGHT JOIN'])) {
152+
unset($criteria['DISTINCT']);
153+
}
154+
144155
Profiler::getInstance()->stop(__METHOD__ . ' build SQL criteria');
145156
$iterator = $DB->request($criteria);
146157

@@ -871,7 +882,7 @@ public static function nbItemByFk(
871882
],
872883
],
873884
],
874-
'GROUPBY' => "$fk_table.$name",
885+
'GROUPBY' => "$fk_table.id",
875886
'ORDERBY' => "cpt DESC",
876887
'LIMIT' => $params['limit'],
877888
],
@@ -1283,6 +1294,14 @@ public static function getTicketsStatus(array $params = []): array
12831294
self::getFiltersCriteria($t_table, $params['apply_filters'])
12841295
);
12851296

1297+
// avoid costly DISTINCT if there isn't any JOIN (/3 perf gain)
1298+
if (!isset($sub_query['LEFT JOIN'])
1299+
&& !isset($sub_query['JOIN'])
1300+
&& !isset($sub_query['INNER JOIN'])
1301+
&& !isset($sub_query['RIGHT JOIN'])) {
1302+
unset($sub_query['DISTINCT']);
1303+
}
1304+
12861305
$criteria = [
12871306
'SELECT' => [
12881307
QueryFunction::fromUnixtime(

0 commit comments

Comments
 (0)