-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[D1] teach wrangler how to fetch insights about D1's queries #4909
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
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
370a687
[D1] teach wrangler how to fetch insights about D1's queries
rozenmd 21fe9de
add options for sorting and number of results
rozenmd d4dafc1
add a means of filtering the datetime geq/leq
rozenmd f915793
add more options, fix tests
rozenmd 24881d6
add wrangler banner, add warning text
rozenmd 6ebc5e6
add changeset
rozenmd 556458e
rename last to timePeriod
rozenmd 6920767
use string format over numbers as >1mo's data could be possible
rozenmd 9f8b5a1
Update red-icons-flow.md
rozenmd e573a8a
make it possible to order by count
rozenmd ef09c6e
Update red-icons-flow.md
rozenmd 61959ce
PR feedback
rozenmd 77f5773
Update .changeset/red-icons-flow.md
rozenmd ec24967
address PR feedback
rozenmd f5ac1ed
Merge branch 'rozenmd/d1-insights' of https://github.com/cloudflare/w…
rozenmd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| --- | ||
| "wrangler": patch | ||
| --- | ||
|
|
||
| feat: add an experimental `insights` command to `wrangler d1` | ||
|
|
||
| This PR adds a `wrangler d1 insights <DB_NAME>` command, to let D1 users figure out which of their queries to D1 need to be optimised. | ||
|
|
||
| This command defaults to fetching the top 5 queries that took the longest to run in total over the last 24 hours. | ||
|
|
||
| You can also fetch the top 5 queries that consumed the most rows read over the last week, for example: | ||
|
|
||
| ```bash | ||
| npx wrangler d1 insights northwind --sortBy reads --timePeriod 7d | ||
| ``` | ||
|
|
||
| Or the top 5 queries that consumed the most rows written over the last month, for example: | ||
|
|
||
| ```bash | ||
| npx wrangler d1 insights northwind --sortBy writes --timePeriod 31d | ||
| ``` | ||
|
|
||
| Or the top 5 most frequently run queries in the last 24 hours, for example: | ||
|
|
||
| ```bash | ||
| npx wrangler d1 insights northwind --sortBy count | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| import { printWranglerBanner } from ".."; | ||
| import { fetchGraphqlResult } from "../cfetch"; | ||
| import { withConfig } from "../config"; | ||
| import { logger } from "../logger"; | ||
| import { requireAuth } from "../user"; | ||
| import { | ||
| d1BetaWarning, | ||
| getDatabaseByNameOrBinding, | ||
| getDatabaseInfoFromId, | ||
| } from "./utils"; | ||
| import type { | ||
| CommonYargsArgv, | ||
| StrictYargsOptionsToInterface, | ||
| } from "../yargs-types"; | ||
| import type { D1QueriesGraphQLResponse, Database } from "./types"; | ||
|
|
||
| export function Options(d1ListYargs: CommonYargsArgv) { | ||
| return d1ListYargs | ||
| .positional("name", { | ||
| describe: "The name of the DB", | ||
| type: "string", | ||
| demandOption: true, | ||
| }) | ||
| .option("timePeriod", { | ||
| choices: ["1d", "7d", "31d"] as const, | ||
| describe: "Fetch data from now to the provided time period", | ||
| default: "1d" as const, | ||
| }) | ||
| .option("sort-type", { | ||
| choices: ["sum", "avg"] as const, | ||
| describe: "Choose the operation you want to sort insights by", | ||
| default: "sum" as const, | ||
| }) | ||
| .option("sort-by", { | ||
| choices: ["time", "reads", "writes", "count"] as const, | ||
| describe: "Choose the field you want to sort insights by", | ||
| default: "time" as const, | ||
| }) | ||
| .option("sort-direction", { | ||
| choices: ["ASC", "DESC"] as const, | ||
| describe: "Choose a sort direction", | ||
| default: "DESC" as const, | ||
| }) | ||
| .option("count", { | ||
| describe: "fetch insights about the first X queries", | ||
| type: "number", | ||
| default: 5, | ||
| }) | ||
| .option("json", { | ||
| describe: "return output as clean JSON", | ||
| type: "boolean", | ||
| default: false, | ||
| }) | ||
| .epilogue(d1BetaWarning); | ||
| } | ||
|
|
||
| const cliOptionToGraphQLOption = { | ||
| time: "queryDurationMs", | ||
| reads: "rowsRead", | ||
| writes: "rowsWritten", | ||
| count: "count", | ||
| }; | ||
|
|
||
| type HandlerOptions = StrictYargsOptionsToInterface<typeof Options>; | ||
| export const Handler = withConfig<HandlerOptions>( | ||
| async ({ | ||
| name, | ||
| config, | ||
| json, | ||
| count, | ||
| timePeriod, | ||
| sortType, | ||
| sortBy, | ||
| sortDirection, | ||
| }): Promise<void> => { | ||
| const accountId = await requireAuth(config); | ||
| const db: Database = await getDatabaseByNameOrBinding( | ||
| config, | ||
| accountId, | ||
| name | ||
| ); | ||
|
|
||
| const result = await getDatabaseInfoFromId(accountId, db.uuid); | ||
|
|
||
| const output: Record<string, string | number>[] = []; | ||
|
|
||
| if (result.version !== "alpha") { | ||
| const convertedTimePeriod = Number(timePeriod.replace("d", "")); | ||
| const endDate = new Date(); | ||
| const startDate = new Date( | ||
| new Date(endDate).setDate(endDate.getDate() - convertedTimePeriod) | ||
| ); | ||
| const parsedSortBy = cliOptionToGraphQLOption[sortBy]; | ||
| const orderByClause = | ||
| parsedSortBy === "count" | ||
| ? `${parsedSortBy}_${sortDirection}` | ||
| : `${sortType}_${parsedSortBy}_${sortDirection}`; | ||
| const graphqlQueriesResult = | ||
| await fetchGraphqlResult<D1QueriesGraphQLResponse>({ | ||
| method: "POST", | ||
| body: JSON.stringify({ | ||
| query: `query getD1QueriesOverviewQuery($accountTag: string, $filter: ZoneWorkersRequestsFilter_InputObject) { | ||
| viewer { | ||
| accounts(filter: {accountTag: $accountTag}) { | ||
| d1QueriesAdaptiveGroups(limit: ${count}, filter: $filter, orderBy: [${orderByClause}]) { | ||
| sum { | ||
| queryDurationMs | ||
| rowsRead | ||
| rowsWritten | ||
| } | ||
| avg { | ||
| queryDurationMs | ||
| rowsRead | ||
| rowsWritten | ||
| } | ||
| count | ||
| dimensions { | ||
| query | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }`, | ||
| operationName: "getD1QueriesOverviewQuery", | ||
| variables: { | ||
| accountTag: accountId, | ||
| filter: { | ||
| AND: [ | ||
| { | ||
| datetimeHour_geq: startDate.toISOString(), | ||
| datetimeHour_leq: endDate.toISOString(), | ||
| databaseId: db.uuid, | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| }), | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| }); | ||
|
|
||
| graphqlQueriesResult?.data?.viewer?.accounts[0]?.d1QueriesAdaptiveGroups?.forEach( | ||
| (row) => { | ||
| if (!row.dimensions.query) return; | ||
| output.push({ | ||
| query: row.dimensions.query, | ||
| avgRowsRead: row?.avg?.rowsRead ?? 0, | ||
| totalRowsRead: row?.sum?.rowsRead ?? 0, | ||
| avgRowsWritten: row?.avg?.rowsWritten ?? 0, | ||
| totalRowsWritten: row?.sum?.rowsWritten ?? 0, | ||
| avgDurationMs: row?.avg?.queryDurationMs ?? 0, | ||
| totalDurationMs: row?.sum?.queryDurationMs ?? 0, | ||
| numberOfTimesRun: row?.count ?? 0, | ||
| }); | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| if (json) { | ||
| logger.log(JSON.stringify(output, null, 2)); | ||
| } else { | ||
| await printWranglerBanner(); | ||
| logger.log( | ||
| "-------------------\n🚧 `wrangler d1 insights` is an experimental command.\n🚧 Flags for this command, their descriptions, and output may change between wrangler versions.\n-------------------\n" | ||
| ); | ||
| logger.log(JSON.stringify(output, null, 2)); | ||
| } | ||
| } | ||
| ); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Should we also be calling
d1BetaWarning()here too?(Actually looking at the rest of the code,
d1BetaWarning()is currently only used in the epilogue... But I wonder if it would be worth reiterating that warning on each function?)