mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-01-16 18:04:34 -05:00
add mysql InnoDB op/sec to performance dashboards
This commit is contained in:
@@ -34,7 +34,7 @@ class MysqlInfo extends \Gazelle\Base {
|
||||
}
|
||||
|
||||
self::$db->prepared_query("
|
||||
SELECT $tableColumn AS table_name,
|
||||
SELECT t.$tableColumn AS table_name,
|
||||
t.ENGINE AS engine,
|
||||
t.ROW_FORMAT AS row_format,
|
||||
sum(t.TABLE_ROWS) AS table_rows,
|
||||
@@ -44,10 +44,21 @@ class MysqlInfo extends \Gazelle\Base {
|
||||
sum(t.INDEX_LENGTH) AS index_length,
|
||||
sum(t.INDEX_LENGTH + t.DATA_LENGTH) AS total_length,
|
||||
sum(t.DATA_FREE) AS data_free,
|
||||
CASE WHEN sum(t.DATA_LENGTH) = 0 THEN 0 ELSE sum(t.DATA_FREE) / sum(t.DATA_LENGTH) END as free_ratio
|
||||
CASE WHEN sum(t.DATA_LENGTH) = 0 THEN 0 ELSE sum(t.DATA_FREE) / sum(t.DATA_LENGTH) END as free_ratio,
|
||||
CASE WHEN wsbt.COUNT_READ + wsbt.COUNT_WRITE + wsbt.COUNT_FETCH
|
||||
+ wsbt.COUNT_INSERT + wsbt.COUNT_UPDATE + wsbt.COUNT_DELETE = 0
|
||||
THEN 0
|
||||
ELSE
|
||||
(wsbt.COUNT_READ + wsbt.COUNT_WRITE + wsbt.COUNT_FETCH
|
||||
+ wsbt.COUNT_INSERT + wsbt.COUNT_UPDATE + wsbt.COUNT_DELETE)
|
||||
/ (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime')
|
||||
END AS iops
|
||||
FROM information_schema.tables t
|
||||
LEFT JOIN information_schema.table_statistics ts USING (table_schema, table_name)
|
||||
WHERE table_schema = ? $where
|
||||
INNER JOIN performance_schema.table_io_waits_summary_by_table wsbt
|
||||
ON (wsbt.OBJECT_SCHEMA = t.TABLE_SCHEMA AND wsbt.OBJECT_NAME = t.TABLE_NAME)
|
||||
LEFT JOIN information_schema.table_statistics ts
|
||||
ON (ts.TABLE_SCHEMA = t.TABLE_SCHEMA AND ts.TABLE_NAME = t.TABLE_NAME)
|
||||
WHERE t.table_schema = ? $where
|
||||
GROUP BY $tableColumn, engine, row_format
|
||||
ORDER BY {$this->orderBy->value} {$this->direction->value}
|
||||
", MYSQL_DB
|
||||
@@ -75,6 +86,8 @@ class MysqlInfo extends \Gazelle\Base {
|
||||
=> ['dbColumn' => MysqlInfoOrderBy::freeRatio->value, 'defaultSort' => 'desc', 'text' => 'Bloat %', 'alt' => 'table bloat'],
|
||||
MysqlInfoOrderBy::avgRowLength->value
|
||||
=> ['dbColumn' => MysqlInfoOrderBy::avgRowLength->value, 'defaultSort' => 'desc', 'text' => 'Row Size', 'alt' => 'mean row length'],
|
||||
MysqlInfoOrderBy::iops->value
|
||||
=> ['dbColumn' => MysqlInfoOrderBy::iops->value, 'defaultSort' => 'desc', 'text' => 'IOPS', 'alt' => 'innodb ops sec'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -93,6 +106,7 @@ class MysqlInfo extends \Gazelle\Base {
|
||||
MysqlInfoOrderBy::dataFree->value => MysqlInfoOrderBy::dataFree,
|
||||
MysqlInfoOrderBy::freeRatio->value => MysqlInfoOrderBy::freeRatio,
|
||||
MysqlInfoOrderBy::avgRowLength->value => MysqlInfoOrderBy::avgRowLength,
|
||||
MysqlInfoOrderBy::iops->value => MysqlInfoOrderBy::iops,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -105,12 +105,21 @@ class MysqlTable extends AbstractTable {
|
||||
t.DATA_LENGTH,
|
||||
t.INDEX_LENGTH,
|
||||
t.DATA_FREE,
|
||||
ts.ROWS_READ,
|
||||
ts.ROWS_CHANGED,
|
||||
ts.ROWS_CHANGED_X_INDEXES
|
||||
coalesce(ts.ROWS_READ, 0) AS ROWS_READ,
|
||||
coalesce(ts.ROWS_CHANGED, 0) AS ROWS_CHANGED,
|
||||
coalesce(ts.ROWS_CHANGED_X_INDEXES, 0) AS ROWS_CHANGED_X_INDEXES,
|
||||
CASE WHEN wsbt.COUNT_READ + wsbt.COUNT_WRITE + wsbt.COUNT_FETCH
|
||||
+ wsbt.COUNT_INSERT + wsbt.COUNT_UPDATE + wsbt.COUNT_DELETE = 0
|
||||
THEN 0
|
||||
ELSE (wsbt.COUNT_READ + wsbt.COUNT_WRITE + wsbt.COUNT_FETCH
|
||||
+ wsbt.COUNT_INSERT + wsbt.COUNT_UPDATE + wsbt.COUNT_DELETE)
|
||||
/ (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Uptime')
|
||||
END AS iops
|
||||
FROM information_schema.tables t
|
||||
INNER JOIN information_schema.table_statistics ts
|
||||
USING (TABLE_SCHEMA, TABLE_NAME)
|
||||
INNER JOIN performance_schema.table_io_waits_summary_by_table wsbt
|
||||
ON (wsbt.OBJECT_SCHEMA = t.TABLE_SCHEMA AND wsbt.OBJECT_NAME = t.TABLE_NAME)
|
||||
LEFT JOIN information_schema.table_statistics ts
|
||||
ON (ts.TABLE_SCHEMA = t.TABLE_SCHEMA AND ts.TABLE_NAME = t.TABLE_NAME)
|
||||
WHERE t.TABLE_SCHEMA = ?
|
||||
AND t.TABLE_NAME = ?
|
||||
", MYSQL_DB, $this->name
|
||||
|
||||
@@ -13,4 +13,5 @@ enum MysqlInfoOrderBy: string {
|
||||
case dataFree = 'data_free';
|
||||
case freeRatio = 'free_ratio';
|
||||
case avgRowLength = 'avg_row_length';
|
||||
case iops = 'iops';
|
||||
}
|
||||
|
||||
@@ -63,5 +63,6 @@ GRANT EXECUTE ON FUNCTION `gazelle`.`binomial_ci` TO 'www'@'localhost';
|
||||
GRANT EXECUTE ON FUNCTION `gazelle`.`bonus_accrual` TO 'www'@'localhost';
|
||||
GRANT SELECT ON `sys`.`schema_unused_indexes` TO 'www'@'localhost';
|
||||
GRANT SELECT ON `performance_schema`.`table_io_waits_summary_by_index_usage` TO 'www'@'localhost';
|
||||
GRANT SELECT ON `performance_schema`.`table_io_waits_summary_by_table` TO 'www'@'localhost';
|
||||
GRANT SELECT ON `sys`.`schema_redundant_indexes` TO 'www'@'localhost';
|
||||
GRANT SELECT ON `sys`.`x$schema_flattened_keys` TO 'www'@'localhost';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_index_usage TO 'gazelle'@'%';
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_table TO 'gazelle'@'%';
|
||||
GRANT SELECT ON sys.schema_redundant_indexes TO 'gazelle'@'%';
|
||||
GRANT SELECT ON sys.schema_unused_indexes TO 'gazelle'@'%';
|
||||
GRANT SELECT ON sys.x$schema_flattened_keys TO 'gazelle'@'%';
|
||||
|
||||
@@ -59,10 +59,12 @@ if [ -z "${MYSQL_INIT_DB-}" ]; then
|
||||
cat <<EOF
|
||||
CREATE USER IF NOT EXISTS 'ro_$MYSQL_USER'@'%' IDENTIFIED BY 'ro_$MYSQL_PASSWORD';
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_index_usage TO '$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_table TO '$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.schema_redundant_indexes TO '$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.schema_unused_indexes TO '$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.x\$schema_flattened_keys TO '$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_index_usage TO 'ro_$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON performance_schema.table_io_waits_summary_by_table TO 'ro_$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.schema_redundant_indexes TO 'ro_$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.schema_unused_indexes TO 'ro_$MYSQL_USER'@'%';
|
||||
GRANT SELECT ON sys.x\$schema_flattened_keys TO 'ro_$MYSQL_USER'@'%';
|
||||
|
||||
@@ -66,6 +66,7 @@ Highcharts.chart('statistics', {
|
||||
<td style="text-align:right" class="nobr">{{ header|column('data_free') }}</td>
|
||||
<td style="text-align:right" class="nobr">{{ header|column('free_ratio') }}</td>
|
||||
<td style="text-align:right" class="nobr">{{ header|column('total_length') }}</td>
|
||||
<td style="text-align:right" class="nobr">{{ header|column('iops') }}</td>
|
||||
</tr>
|
||||
|
||||
{% set total_rows = 0 %}
|
||||
@@ -73,12 +74,14 @@ Highcharts.chart('statistics', {
|
||||
{% set total_data_size = 0 %}
|
||||
{% set total_index_size = 0 %}
|
||||
{% set total_free_size = 0 %}
|
||||
{% set total_iops = 0 %}
|
||||
{% for t in list -%}
|
||||
{%- set total_rows = total_rows + t.table_rows -%}
|
||||
{%- set total_rows_read = total_rows_read + t.rows_read -%}
|
||||
{%- set total_data_size = total_data_size + t.data_length -%}
|
||||
{%- set total_index_size = total_index_size + t.index_length -%}
|
||||
{%- set total_free_size = total_free_size + t.data_free -%}
|
||||
{%- set total_iops = total_iops + t.iops -%}
|
||||
<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
|
||||
<td><a href="tools.php?action=db-mysql&table={{ t.table_name }}" title="engine: {{ t.engine }}">
|
||||
{%- if t.engine != 'InnoDB' %}<span style="color: tomato;">{% endif -%}
|
||||
@@ -94,6 +97,7 @@ Highcharts.chart('statistics', {
|
||||
<td class="number_column">{{ t.data_free|octet_size }}</td>
|
||||
<td class="number_column">{{ t.free_ratio|number_format(2) }}</td>
|
||||
<td class="number_column">{{ t.total_length|octet_size }}</td>
|
||||
<td class="number_column">{{ t.iops|number_format(2) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
@@ -105,6 +109,7 @@ Highcharts.chart('statistics', {
|
||||
<td class="number_column"><b>{{ total_free_size|octet_size }}</b></td>
|
||||
<td class="number_column"><b>{% if total_data_size %}{{ (total_free_size / total_data_size * 100)|number_format(2) }}{% else %}0{% endif %}</b></td>
|
||||
<td class="number_column"><b>{{ (total_data_size + total_index_size)|octet_size }}</b></td>
|
||||
<td class="number_column"><b>{{ total_iops|number_format(2) }}</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
{{ footer() }}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<th>Rows read</th>
|
||||
<th>Rows changed</th>
|
||||
<th>Rows changed per index</th>
|
||||
<th>IOPS</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ table.stats.TABLE_ROWS|number_format }}</td>
|
||||
@@ -35,6 +36,7 @@
|
||||
<td>{{ table.stats.ROWS_READ|number_format }}</td>
|
||||
<td>{{ table.stats.ROWS_CHANGED|number_format }}</td>
|
||||
<td>{{ table.stats.ROWS_CHANGED_X_INDEXES|number_format }}</td>
|
||||
<td>{{ table.stats.iops|number_format(2) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div></div>
|
||||
|
||||
@@ -345,6 +345,7 @@ class DbTest extends TestCase {
|
||||
[
|
||||
"TABLE_ROWS", "AVG_ROW_LENGTH", "DATA_LENGTH", "INDEX_LENGTH",
|
||||
"DATA_FREE", "ROWS_READ", "ROWS_CHANGED", "ROWS_CHANGED_X_INDEXES",
|
||||
"iops",
|
||||
],
|
||||
array_keys($table->stats()),
|
||||
'mysql-table-stats',
|
||||
|
||||
@@ -9,13 +9,25 @@ use Gazelle\Enum\MysqlTableMode;
|
||||
|
||||
class MysqlInfoTest extends TestCase {
|
||||
public function testDirection(): void {
|
||||
$this->assertEquals(MysqlInfoOrderBy::totalLength, DB\MysqlInfo::lookupOrderby('total_length'), 'mysqlfo-orderby-totallength');
|
||||
$this->assertEquals(MysqlInfoOrderBy::tableName, DB\MysqlInfo::lookupOrderby('table_name'), 'mysqlfo-orderby-tablename');
|
||||
$this->assertEquals(MysqlInfoOrderBy::tableName, DB\MysqlInfo::lookupOrderby('wut'), 'mysqlfo-orderby-default');
|
||||
$this->assertEquals(
|
||||
MysqlInfoOrderBy::totalLength,
|
||||
DB\MysqlInfo::lookupOrderby('total_length'),
|
||||
'mysqlfo-orderby-totallength',
|
||||
);
|
||||
$this->assertEquals(
|
||||
MysqlInfoOrderBy::tableName,
|
||||
DB\MysqlInfo::lookupOrderby('table_name'),
|
||||
'mysqlfo-orderby-tablename',
|
||||
);
|
||||
$this->assertEquals(
|
||||
MysqlInfoOrderBy::tableName,
|
||||
DB\MysqlInfo::lookupOrderby('wut'),
|
||||
'mysqlfo-orderby-default',
|
||||
);
|
||||
}
|
||||
|
||||
public function testMysqlInfoColumn(): void {
|
||||
$this->assertCount(9, DB\MysqlInfo::columnList(), 'myinfo-column-list');
|
||||
$this->assertCount(10, DB\MysqlInfo::columnList(), 'myinfo-column-list');
|
||||
}
|
||||
|
||||
public function testMysqlInfoList(): void {
|
||||
|
||||
Reference in New Issue
Block a user