Skip to content

Commit

Permalink
db-stats improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
mi7chal committed Sep 25, 2024
1 parent 4bc67c3 commit 6289773
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 32 deletions.
156 changes: 126 additions & 30 deletions Moosh/Command/Moodle39/Report/DbStats.php
Original file line number Diff line number Diff line change
@@ -1,55 +1,151 @@
<?php
/**
* moosh - Moodle Shell
*
* @copyright 2012 onwards Tomasz Muras
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/


namespace Moosh\Command\Moodle39\Report;

use Moosh\MooshCommand;

const TABLE_NAMES = [
"log" => "mdl_log",
"grades" => "mdl_grade_grades",
"grades_history" => "mdl_grade_grades_history",
];



/**
* Command returns moodle database stats. For format check Moosh web docs.
*/
class DbStats extends MooshCommand {
public function __construct() {
parent::__construct('stats', 'db');

$this->addOption('j|json', 'generate output using json format');
$this->addOption('e|extended', 'generate extended stats for every table, always in json');
$this->addOption('H|no-human-readable', 'Do not display sizes in human-readble strings');
}

public function execute() {
$options = $this->expandedOptions;

if(isset($options['extended'])) {
$results = $this->fetchStats();

// returns full json stats
$results->tables = array_values($results->tables);

echo json_encode($results);
} else {
// returns minimal stats
$results = $this->fetchStats(3, array_values(TABLE_NAMES));

// non-breaking space prevents from formatting as size
foreach($results->tables as $key => $table) {
$results->tables[$key]->rowCount = $table->rowCount . "\u{00A0}";
}

$stats = $this->mapStatsToSimpleFormat($results);

$this->display($stats, $options['json'], !$options['no-human-readable']);
}
}

/**
* Fetches database stats and returns plain results. Returns object containing size (int)
* and tables (array). Additionally, method may include tables provided in $additionalTableStats argument.
* @param non-negative-int|null $limit results limit
* @param string[] $additionalTableStats array of table names
* @return object
*/
public function fetchStats($limit = null, $additionalTableStats = []) {
global $DB, $CFG;

$options = $this->expandedOptions;
if($limit < 0 || !($limit === null || is_int($limit))) {
throw new \InvalidArgumentException("limit must be a positive integer or null.");
}

if(!is_array($additionalTableStats)) {
throw new \InvalidArgumentException("additionalTableStats must be an array.");
}

// fetching general info
$informationSchemaSql = "
SELECT table_name AS 'name',
ROUND(data_length + index_length) AS 'size'
FROM information_schema.TABLES
WHERE table_schema = '$CFG->dbname'
ORDER BY (data_length + index_length) DESC
";

$results = $DB->get_records_sql($informationSchemaSql);

// formatting query result, adding row count and calculating size
$values = array_values($results);
$resultsLength = count($values);
if(is_null($limit) || $limit > $resultsLength) {
$limit = $resultsLength;
}

$databaseSize = 0;
$tableData = [];
foreach($values as $index => $result) {
$databaseSize += $result->size;

$sql = "SELECT table_name AS 'table',
ROUND(((data_length + index_length))) AS 'size'
FROM information_schema.TABLES
WHERE table_schema = '" . $CFG->dbname . "'
ORDER BY (data_length + index_length) DESC";
$results = $DB->get_records_sql($sql);

$databasesize = 0;
$topsizes = [];
$topnames = [];
foreach ($results as $result) {
if (!isset($topsizes[0])) {
$topsizes[0] = $result->size;
$topnames[0] = $result->table;
} else if (!isset($topsizes[1])) {
$topsizes[1] = $result->size;
$topnames[1] = $result->table;
} else if (!isset($topsizes[2])) {
$topsizes[2] = $result->size;
$topnames[2] = $result->table;
// we only calculate size and skips other actions when limit is reached
// we include tables from additionalTableStats
if($index >= $limit && !in_array($result->name, $additionalTableStats)) {
continue;
}
$databasesize += $result->size;

// querying row count
$tableName = $result->name;

$countResult = $DB->get_records_sql("SELECT COUNT(*) AS 'count' from $tableName");

$firstRow = array_values($countResult)[0];

$result->rowCount = strval($firstRow->count);

$tableData[$result->name] = $result;
}

$data = ['Database size' => $databasesize,
'Biggest table name' => $topnames[0],
'Biggest table size' => $topsizes[0],
'2nd biggest table name' => $topnames[1],
'2nd biggest table size' => $topsizes[1],
'3rd biggest table name' => $topnames[2],
'3rd biggest table size' => $topsizes[2],
return (object) [
'size' => $databaseSize,
'tables' => $tableData
];
}

$this->display($data, $options['json'], !$options['no-human-readable']);
/**
* Maps results to array with simple keys and values.
* @param \stdClass $results full stats data
* @return array stat names with values
*/
public function mapStatsToSimpleFormat($results) {
$tables = $results->tables;
$tablesIndexed = array_values($tables);

return ['Database size' => $results->size,
'Biggest table name' => $tablesIndexed[0]->name,
'Biggest table size' => $tablesIndexed[0]->size,
'Biggest table number of records' => $tablesIndexed[0]->rowCount,
'2nd biggest table name' => $tablesIndexed[1]->name,
'2nd biggest table size' => $tablesIndexed[1]->size,
'2nd biggest table number of records' => $tablesIndexed[1]->rowCount,
'3rd biggest table name' => $tablesIndexed[2]->name,
'3rd biggest table size' => $tablesIndexed[2]->size,
'3rd biggest table number of records' => $tablesIndexed[2]->rowCount,
'Log table size' => $tables[TABLE_NAMES['log']]->size,
'Log table number of records' => $tables[TABLE_NAMES['log']]->rowCount,
'Grades table size' => $tables[TABLE_NAMES['grades']]->size,
'Grades table number of records' => $tables[TABLE_NAMES['grades']]->rowCount,
'Grades history table size' => $tables[TABLE_NAMES['grades_history']]->size,
'Grades history table number of records' => $tables[TABLE_NAMES['grades_history']]->rowCount,
];
}
}
10 changes: 8 additions & 2 deletions www/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1084,8 +1084,10 @@ Outputs data in json format when run using --json option.
db-stats
--------

Shows the total size of the Moodle database and the biggest tables.
With -H or -j options the sizes will be shown in bytes (ie "286720" instead of "280KB").
Shows the total size of the Moodle database, the top 3 biggest tables and tables: log, grades, grades history.
With -H, -j or -e options the sizes will be shown in bytes (ie "286720" instead of "280KB").

Using extended option (-e) it shows all tables.

Example 1: Show me basic database statistics, formatted for human consumption.

Expand All @@ -1094,6 +1096,10 @@ Example 1: Show me basic database statistics, formatted for human consumption.
Example 2: Database statistics in JSON format.

moosh db-stats -j

Example 3: Extended database statistics in json format. It provides statistics for each table

moosh db-stats -e

debug-off
---------
Expand Down

0 comments on commit 6289773

Please sign in to comment.