Repository navigation
feat(sqllab): Add optional pre-run query cost warnings - #45313
elizabeth-ilina wants to merge 67 commits into
Conversation
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
CodeAnt PR Risk: Medium Risk
Assessed commit: |
This reverts commit c01ed6b. Keep the shared build-system change separate from the query cost warning feature.
| """Validate replacement or retained settings without adding omitted extra.""" | ||
| assert self._model | ||
| serialized_extra = self._properties.get("extra", self._model.extra) or "{}" | ||
| if "query_cost_warning" not in serialized_extra: |
There was a problem hiding this comment.
This gate does a substring test on the raw extra string, so a JSON-escaped key ("\u0071uery_cost_warning") skips it. extra_validator only runs QueryWarningRuleSchema over the parsed value, so an update with threshold: -1 or a metric the engine doesn't support is stored without the engine/threshold validation, and the Run-time check then returns 400 for that connection. Could this test the parsed extra dict for the key instead (parsing first, as normalize_query_cost_warning already does)?
There was a problem hiding this comment.
Hey, thanks for catching this. Fixed by parsing the JSON before checking for the warning setting. Added regression coverage for escaped keys in both submitted and retained settings, including invalid thresholds and unsupported metrics.
| } | ||
| timeout = app.config["SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT"] | ||
| try: | ||
| with utils.timeout( |
There was a problem hiding this comment.
The new utils.timeout(...) wrapper around check.assess isn't covered. test_warning_known_timeout_is_unavailable has the mocked check raise SupersetTimeoutException directly, so it would still pass if this wrapper were removed or ignored SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT, and a slow estimate would then block Run indefinitely. Could a command-level test patch utils.timeout and assert it is entered with the configured seconds, then that the confirm/unavailable result is returned when it raises?
There was a problem hiding this comment.
Thanks, agreed - the previous test only covered handling the exception. Updated it to check that the timeout context is entered with the configured duration, and that a timeout returns confirm/unavailable without calling the estimator.
| {"query": []}, | ||
| {"query": {"totalBytesProcessed": "1"}}, | ||
| {"rowLevelSecurityStatistics": "masked"}, | ||
| {"rowLevelSecurityStatistics": {"rowLevelSecurityApplied": "false"}}, |
There was a problem hiding this comment.
The string-valued rowLevelSecurityApplied case has no totalBytesProcessed or accuracy, so _query_cost_warning_estimate returns an unusable estimate for it even if the boolean check in bigquery.py is removed, and this assertion still passes. A regression there could let a dry run with malformed row-security metadata but a valid byte count return proceed. Could this case also include "totalBytesProcessed": "1" and "totalBytesProcessedAccuracy": "PRECISE" so it fails without the guard?
There was a problem hiding this comment.
Thanks, fixed. The case now includes a valid byte count and PRECISE accuracy, so it specifically tests the row-security guard. I also fixed a few other test issues: mock leakage between tests, cancellation assertions that ran too early, and malformed-response cases that weren't testing the intended guard.
| MagicMock(), | ||
| False, | ||
| ) | ||
| execute._set_query_limit_if_required(sql) |
There was a problem hiding this comment.
These assertions check the prepared SQL limit but not limiting_factor, so they still pass if every assignment is removed from the shared set_query_limit. The only tests that assert those values (sqllab_tests.py) are skipped, so a wrong attribution would change the truncated-result guidance with nothing failing. Could a unit test on set_query_limit assert QUERY for SQL limit 5 / dropdown 100, DROPDOWN for 500 / 100, and QUERY_AND_DROPDOWN for 100 / 100?
There was a problem hiding this comment.
Thanks, added unit coverage for all three cases, asserting both the effective limit and limiting_factor.
SUMMARY
Add optional cost warnings to SQL Lab's Run workflow, initially supporting BigQuery and PostgreSQL. Users can review an expensive query before it executes. This is an advisory warning, not an enforced spending or resource limit.
The operator enables
SQLLAB_QUERY_COST_WARNINGSandESTIMATE_QUERY_COST. An administrator then opens Database Connections > Edit > Advanced > SQL Lab, enables query cost estimation and pre-run cost warnings, and sets a threshold for that connection. The new warning feature is off by default; no threshold is chosen automatically. The rule is stored in the connection's existingextraJSON, without a database migration.Each engine uses its own metric:
EXPLAIN (FORMAT JSON), withoutANALYZE. This is a relative cost, not dollars, memory or execution time.For a configured connection, Run checks the query before submitting execution:
The comparison uses raw values before display rounding. Estimation uses the query's execution context and effective row limit. Cancelling or changing relevant inputs invalidates the pending attempt; repeated confirmation submits the query once.
The Run tooltip shows when warnings are enabled and the configured metric and threshold. The manual estimator remains available with its existing formatted response. Disabled warnings skip the estimate request. Engine hooks define support, so unsupported connections do not acquire arbitrary warning rules.
This covers deliberate SQL Lab runs, including keyboard, selection and query-history entry points. Dashboard queries, scheduled execution and CTAS/CVAS are outside this change. Templates, multiple statements and custom SQL transformations do not receive a pre-run estimate in this implementation.
BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
Before: SQL Lab offers manual estimation, but Run does not compare the estimate against a connection threshold.
After: administrators configure a warning rule, users can see it in the Run tooltip, and expensive queries prompt before execution.
BigQuery settings
PostgreSQL settings
Run tooltip
BigQuery warning
PostgreSQL warning
TESTING INSTRUCTIONS
bigquery-public-data.samples.shakespeareestimates more work than selecting onlyword, even withLIMIT 1. The narrower query should fall below this example threshold. These are demonstration values, not suggested defaults.Validation evidence:
38eff85d7fcovered real BigQuery and PostgreSQL warning/revision flows. BigQuery estimated scanning fell from 6,432,064 to 1,332,943 bytes by selecting only the needed column. A PostgreSQL fixture changed from a sequential scan to an index scan after removing an unnecessary cast; planner cost fell from 459 to 8.3 and both queries returned the same result.54b3c9bb0cwas rendered in the browser. Core execution behavior was not changed by that commit.Local validation does not replace the required GitHub checks. Keep the PR draft until those checks have completed successfully.
ADDITIONAL INFORMATION
SQLLAB_QUERY_COST_WARNINGS,ESTIMATE_QUERY_COST