# Insights panel > A side panel that tells you where a query's bytes go before you run it, and where its time went after. Cost is broken down per CTE, pipe stage, subquery, and statement, from BigQuery dry runs, so you optimize the section that matters instead of guessing. Source: https://docs.querylab.io/writing-sql/insights-panel/ **Prism Insights → Costs Debug** **PRISM INSIGHTS** - : Costs Debug Analyze
Mode Section Column
Filter Propagation
Cost Breakdown
Generated: 2026-02-14 15:10:37
Total Query Estimate
Total Cost: $0.00
Total Bytes: 679.6 MB
CTEs (2)
failed_testsCost: $0.02 >100% of total
Bytes: 3.64 GB
dangerous_defectsCost: $0.00 66% of total
Bytes: 451.39 MB
Statements (1)
Main QueryCost: $0.00 100% of total
Bytes: 679.6 MB
The whole query scans 679.6 MB. failed_tests on its own would scan 3.64 GB; the note below explains why a part can cost more than the whole. ## Opening it Any of these opens the panel on the right of the editor: - The ⋮ menu in the header → **Prism Insights** - Right-click in the editor → **Show Prism Insights** - `F1` in the editor → **Show Prism Insights** The panel has four views: | View | When it has content | What it shows | | ------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **Costs Debug** | After you click **Analyze** | Bytes and cost per section of the query, from dry runs | | **Execution Plan** | After a query runs | Stages, row counts, detected performance issues; see [Execution plan](https://docs.querylab.io/writing-sql/execution-plan/) | | **Model Hint** | Always | Whether on-demand or a reservation would be cheaper for this query; see [Pricing comparison](https://docs.querylab.io/writing-sql/pricing-comparison/) | | **Lineage** | As you type | Which source columns feed each output column; see [Column lineage](https://docs.querylab.io/writing-sql/lineage/) | ## Breaking cost down by section Click **Analyze**. Querylab.io splits the query at its execution boundaries (each CTE, each pipe `|>` stage, each subquery, each set-operation branch, each statement of a script) and dry-runs the query up to each boundary. Dry runs are free. **Cancel** stops it. The result is grouped by kind: **CTEs**, **Pipes**, **Subqueries**, **Set Operations**, **Statements**. Each entry shows its bytes, its cost at the tab's pricing, and its share of the total. The **Total Query Estimate** box at the top is the dry run of the whole query, the same number the editor's status bar shows. Hover an entry for the copy icon: it copies the exact SQL that was dry-run for that section, which is the fastest way to see what "up to this CTE" means. > **A section can exceed 100% of the total.** Each section is dry-run as a standalone query (`WITH failed_tests AS (…) SELECT * FROM failed_tests`), so it reads every column the CTE produces. The whole query only reads the columns the final SELECT needs, and BigQuery bills by column, so the whole can cost less than one of its parts. The amber{" "} >100% of total pill marks these; they're candidates for a narrower SELECT list. Same gutter, different entry point: the diamond icons in the editor margin estimate or run a single section without opening the panel; see [Partial execution](https://docs.querylab.io/writing-sql/partial-execution/). ## Choosing section or column mode The **Mode** switch chooses what the analysis breaks down by. **Section**, the default, dry-runs each boundary and finds the expensive CTE, pipe stage, or statement. **Column** dry-runs each selected column instead, for wide tables where you want to know which columns of a `SELECT` list are expensive to read. Column mode replaces the cost breakdown with a **Column Cost Breakdown** card that has three tabs: **By Column** (each column's bytes, with **Expensive** marked at over 10% of the total and **Partition** / **Cluster** columns flagged), **JOIN Impact** (how each join changes row counts), and **By Table**. Left alone, the panel picks a mode for you. ## Propagating filters upstream **Filter Propagation** is on by default. When it's on, a `WHERE` in a downstream section is applied to the upstream CTEs it filters when they are estimated, the same pushdown BigQuery does at run time. Off, every CTE is estimated as written, which is the number you want when you're deciding whether a CTE needs its own filter.