-
Notifications
You must be signed in to change notification settings - Fork 28
DA-1203 Modified Add Slow Running Queries tools #74
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
Changes from all commits
4a25f18
aa864e2
0a8a962
6972b64
aca35a6
adea7b7
029a7a9
6c62c62
cf65885
1a2b288
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -89,7 +89,6 @@ def run_sql_plus_plus_query( | |||||||||||||||||
| raise | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| # Don't expose this function to the MCP server until we have a use case | ||||||||||||||||||
| def run_cluster_query(ctx: Context, query: str, **kwargs: Any) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Run a query on the cluster object and return the results as a list of JSON objects.""" | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -104,3 +103,258 @@ def run_cluster_query(ctx: Context, query: str, **kwargs: Any) -> list[dict[str, | |||||||||||||||||
| except Exception as e: | ||||||||||||||||||
| logger.error(f"Error running query: {e}") | ||||||||||||||||||
| raise | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx: Context, | ||||||||||||||||||
| query: str, | ||||||||||||||||||
| *, | ||||||||||||||||||
| limit: int, | ||||||||||||||||||
| empty_message: str, | ||||||||||||||||||
| extra_payload: dict[str, Any] | None = None, | ||||||||||||||||||
| **query_kwargs: Any, | ||||||||||||||||||
| ) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Execute a cluster query with a consistent empty-result response.""" | ||||||||||||||||||
| results = run_cluster_query(ctx, query, limit=limit, **query_kwargs) | ||||||||||||||||||
|
|
||||||||||||||||||
| if results: | ||||||||||||||||||
| return results | ||||||||||||||||||
|
|
||||||||||||||||||
| payload: dict[str, Any] = {"message": empty_message, "results": []} | ||||||||||||||||||
| if extra_payload: | ||||||||||||||||||
| payload.update(extra_payload) | ||||||||||||||||||
| return [payload] | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_longest_running_queries(ctx: Context, limit: int = 10) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get the N longest running queries from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries with their average service time and count | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT statement, | ||||||||||||||||||
| DURATION_TO_STR(avgServiceTime) AS avgServiceTime, | ||||||||||||||||||
| COUNT(1) AS queries | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE UPPER(statement) NOT LIKE 'INFER %' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE PRIMARY INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
| GROUP BY statement | ||||||||||||||||||
| LETTING avgServiceTime = AVG(STR_TO_DURATION(serviceTime)) | ||||||||||||||||||
| ORDER BY avgServiceTime DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No completed queries were available to calculate longest running queries." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_most_frequent_queries(ctx: Context, limit: int = 10) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get the N most frequent queries from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries with their frequency count | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT statement, | ||||||||||||||||||
| COUNT(1) AS queries | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE UPPER(statement) NOT LIKE 'INFER %' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE PRIMARY INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'EXPLAIN %' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'ADVISE %' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
| GROUP BY statement | ||||||||||||||||||
| LETTING queries = COUNT(1) | ||||||||||||||||||
| ORDER BY queries DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No completed queries were available to calculate most frequent queries." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_queries_with_largest_response_sizes( | ||||||||||||||||||
| ctx: Context, limit: int = 10 | ||||||||||||||||||
| ) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get queries with the largest response sizes from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries with their average result size in bytes, KB, and MB | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT statement, | ||||||||||||||||||
| avgResultSize AS avgResultSizeBytes, | ||||||||||||||||||
| (avgResultSize / 1000) AS avgResultSizeKB, | ||||||||||||||||||
| (avgResultSize / 1000000) AS avgResultSizeMB, | ||||||||||||||||||
| COUNT(1) AS queries | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE UPPER(statement) NOT LIKE 'INFER %' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE 'CREATE PRIMARY INDEX%' | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
| GROUP BY statement | ||||||||||||||||||
| LETTING avgResultSize = AVG(resultSize) | ||||||||||||||||||
| ORDER BY avgResultSize DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No completed queries were available to calculate response sizes." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_queries_with_large_result_count( | ||||||||||||||||||
| ctx: Context, limit: int = 10 | ||||||||||||||||||
| ) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get queries with the largest result counts from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries with their average result count | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT statement, | ||||||||||||||||||
| avgResultCount, | ||||||||||||||||||
| COUNT(1) AS queries | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE UPPER(statement) NOT LIKE 'INFER %' AND | ||||||||||||||||||
| UPPER(statement) NOT LIKE 'CREATE INDEX%' AND | ||||||||||||||||||
| UPPER(statement) NOT LIKE 'CREATE PRIMARY INDEX%' AND | ||||||||||||||||||
| UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
| GROUP BY statement | ||||||||||||||||||
| LETTING avgResultCount = AVG(resultCount) | ||||||||||||||||||
| ORDER BY avgResultCount DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No completed queries were available to calculate result counts." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_queries_using_primary_index( | ||||||||||||||||||
| ctx: Context, limit: int = 10 | ||||||||||||||||||
| ) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get queries that use a primary index from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries that use primary indexes, ordered by result count | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT * | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE phaseCounts.`primaryScan` IS NOT MISSING | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
|
Comment on lines
+286
to
+287
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency with other query-analyzing tools in this file, consider filtering out
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are adding INFER and SYSTEM, might as well add explain and advise as well- for consistency |
||||||||||||||||||
| ORDER BY resultCount DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No queries using the primary index were found in system:completed_requests." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_queries_not_using_covering_index( | ||||||||||||||||||
| ctx: Context, limit: int = 10 | ||||||||||||||||||
| ) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get queries that don't use a covering index from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries that perform index scans but also require fetches (not covering) | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT * | ||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE phaseCounts.`indexScan` IS NOT MISSING | ||||||||||||||||||
| AND phaseCounts.`fetch` IS NOT MISSING | ||||||||||||||||||
| AND UPPER(statement) NOT LIKE '% SYSTEM:%' | ||||||||||||||||||
|
Comment on lines
+316
to
+318
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This query is missing filters for
Suggested change
|
||||||||||||||||||
| ORDER BY resultCount DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No queries that require fetches after index scans were found " | ||||||||||||||||||
| "in system:completed_requests." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def get_queries_not_selective(ctx: Context, limit: int = 10) -> list[dict[str, Any]]: | ||||||||||||||||||
| """Get queries that are not very selective from the system:completed_requests catalog. | ||||||||||||||||||
|
|
||||||||||||||||||
| Args: | ||||||||||||||||||
| limit: Number of queries to return (default: 10) | ||||||||||||||||||
|
|
||||||||||||||||||
| Returns: | ||||||||||||||||||
| List of queries where index scans return significantly more documents than the final result | ||||||||||||||||||
| """ | ||||||||||||||||||
| query = """ | ||||||||||||||||||
| SELECT statement, | ||||||||||||||||||
| AVG(phaseCounts.`indexScan` - resultCount) AS diff | ||||||||||||||||||
AayushTyagi1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
| FROM system:completed_requests | ||||||||||||||||||
| WHERE phaseCounts.`indexScan` > resultCount | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This query is missing filters to exclude system-level statements (like
Suggested change
|
||||||||||||||||||
| GROUP BY statement | ||||||||||||||||||
| ORDER BY diff DESC | ||||||||||||||||||
| LIMIT $limit | ||||||||||||||||||
| """ | ||||||||||||||||||
|
|
||||||||||||||||||
| return _run_query_tool_with_empty_message( | ||||||||||||||||||
| ctx, | ||||||||||||||||||
| query, | ||||||||||||||||||
| limit=limit, | ||||||||||||||||||
| empty_message=( | ||||||||||||||||||
| "No non-selective queries were found in system:completed_requests." | ||||||||||||||||||
| ), | ||||||||||||||||||
| ) | ||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
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.
For every query that we run via UI, we also run explain and advise on it.
So you might also need to filter out explain and advise for top most frequent queries