-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add index and table metrics to vttablet #17570
base: main
Are you sure you want to change the base?
Conversation
* IndexBytes * IndexCardinality * TableClusteredIndexSize * TableRows Signed-off-by: Rafer Hazen <rafer@ralua.com>
Review ChecklistHello reviewers! 👋 Please follow this checklist when reviewing this Pull Request. General
Tests
Documentation
New flags
If a workflow is added or modified:
Backward compatibility
|
Signed-off-by: Rafer Hazen <rafer@ralua.com>
Signed-off-by: Rafer Hazen <rafer@ralua.com>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #17570 +/- ##
==========================================
- Coverage 67.71% 67.65% -0.06%
==========================================
Files 1584 1585 +1
Lines 254721 256592 +1871
==========================================
+ Hits 172473 173608 +1135
- Misses 82248 82984 +736 ☔ View full report in Codecov by Sentry. |
@@ -432,7 +444,7 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { | |||
// We therefore don't want to query for table sizes in getTableData() | |||
includeStats = false | |||
|
|||
innodbResults, err := conn.Conn.Exec(ctx, innodbTableSizesQuery, maxTableCount, false) | |||
innodbResults, err := conn.Conn.Exec(ctx, innodbTableSizesQuery, maxTableCount*maxPartitionsPerTable, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Increased this because even with our limit of 10k tables, it's possible that there are more partitions than that (and this query returns one row per partition).
@@ -404,6 +404,10 @@ func TestReloadView(t *testing.T) { | |||
db.AddQuery("SELECT TABLE_NAME, CREATE_TIME FROM _vt.`tables`", &sqltypes.Result{}) | |||
// adding query pattern for udfs | |||
db.AddQueryPattern("SELECT name.*", &sqltypes.Result{}) | |||
db.AddQuery("select table_name, partition_name from information_schema.partitions where table_schema = database() and partition_name is not null", &sqltypes.Result{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love that these queries have leaked out of the schema
package, but I can't think of better way to make this test pass (unless we want to make the query constants public). Interested if this causes anyone concern.
@@ -466,8 +478,12 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { | |||
} | |||
} | |||
} | |||
if err := se.updateTableIndexMetrics(ctx, conn.Conn); err != nil { | |||
log.Errorf("Updating index/table statistics failed, error: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just logs instead of failing the method. I figure if updateTableIndexMetrics
fails it's better to continue on since the only impact is missing metrics.
@deepthi We're hoping to keep moving forward on https://github.com/planetscale/surfaces/issues/2679 and this change is (unfortunately!) a blocker. Would you be able to help us get it into the queue for review? If it already is, ignore me! |
if strings.Contains(tableName, "#p#") { | ||
if partition, ok := partitions[tableName]; ok { | ||
tableName = partition.table | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we not directly check in partitions map instead of doing a contains check?
if strings.Contains(tableName, "#p#") { | ||
if partition, ok := partitions[tableName]; ok { | ||
tableName = partition.table | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
|
||
// fetch a list of all partitions | ||
fetchPartitions = `select table_name, partition_name from information_schema.partitions where table_schema = database() and partition_name is not null` | ||
|
||
// fetch the estimated number of rows and the clustered index byte size for all tables | ||
fetchTableRowCountClusteredIndex = `select table_name, n_rows, clustered_index_size * @@innodb_page_size from mysql.innodb_table_stats where database_name = database()` | ||
|
||
// fetch the byte size of all indexes | ||
fetchIndexSizes = `select table_name, index_name, stat_value * @@innodb_page_size from mysql.innodb_index_stats where database_name = database() and stat_name = 'size'` | ||
|
||
// fetch the cardinality of all indexes | ||
fetchIndexCardinalities = `select table_name, index_name, max(cardinality) from information_schema.statistics s where table_schema = database() group by s.table_name, s.index_name` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be added to mysql flavor, otherwise import from mysql 5.7 will complain if the table or column does not exist
@@ -1090,6 +1090,30 @@ func TestEngineReload(t *testing.T) { | |||
}) | |||
} | |||
|
|||
func TestUpdateTableIndexMetrics(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have tables with partitions in this e2e test.
Is it possible to validate the value than checking for nil?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Description
This adds the following metrics to vttablet's schema engine.
TableRows
(by table) - The estimated number of rows in the tableTableClusteredIndexSize
(by table) - The size of the clustered index (i.e. the size of the "row data")IndexCardinality
(by index) - The estimated number of unique values in the indexIndexBytes
(by index) - The size of the indexmetrics sample
These values are read from mysql system tables when
Engine#Reload
is called, and made available viaEnv#Exporter
Partition names
Since mysql implements partitions internally as one table per partition, the "table name" referenced in the stats tables mostly look like
TABLE_NAME#p#PARTITION_NAME
. We want to report statistics per logical table (not per partition) so we need a way to extract the underlying table name. Unfortunately, it's not as simple as splitting the composite name by#p#
, because it's possible to create a table or partition with#p#
as a part of the name.The approach I took here is to load the
information_schema.partitions
table, which includes separate columns for the table and partition name. Then, as we read through the stats tables that contain the composite name, if we encounter a#p#
, we attempt to find a matching table/partition in the loaded list, and, if it is present, we can find the base table name.An alternative method would be to make use of
information_schema.innodb_tables.name
column (like we do here), which provides the table name with special characters encoded. This makes it possible to confidently split on#p#
, because the#
characters would be encoded if they were part of the real table or partition name. I opted for the "loading all partitions" approach instead because the joins required to get an encoded table name made the queries too slow when there are many tables, indexes or partitions.Performance
Since performance of the queries run on
#Reload
has been an issue in the past, I tested the queries added in this PR with the following test setup.Results:
updateTableIndexMetrics
method:716ms
37ms
15ms
205ms
427ms
For comparison the
InnoDBTableSizes
query takes2.0s
for the same test setup.Related Issue(s)
Checklist
Deployment Notes
None