Audit SQL queries for cost and performance issues
Static SQL analyzer that audits queries for 20 cost and performance anti-patterns, scores warehouse health 0-100, and outputs a prioritized fix plan for
Maintainer of this project? Claim this page to edit the listing.
1.0.0Add to Favorites
Why it matters
Automatically review warehouse SQL queries for the 22 most expensive anti-patterns-cross joins, SELECT *, missing partition filters, non-sargable predicates-and generate a prioritized cost-reduction plan with estimated savings, replacing hour-long manual reviews with millisecond static analysis.
Outcomes
What it gets done
Score queries 0-100 and flag critical patterns like CROSS JOINs that turn $0.02 queries into $200 bills
Detect non-sargable predicates (LIKE '%term', LOWER(col)) that defeat indexes and force full scans
Identify missing WHERE clauses, partition filters, and SELECT * on wide tables that waste 30-90% of bytes scanned
Output prioritized findings with why/fix explanations and estimated savings for BigQuery, Snowflake, Redshift, and Postgres
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/ag-sql-sentinel | bash Overview
Sql Sentinel
A static SQL analyzer that catches 20 cost and performance anti-patterns across BigQuery, Snowflake, Redshift, and Postgres, scoring query health 0-100 and delivering a prioritized fix plan. Use when reviewing queries before production, investigating slow queries or high warehouse bills, or running FinOps cost-reduction initiatives. Do not use as a substitute for query-plan analysis or billing data.
What it does
sql-sentinel is a static-analysis skill that audits SQL for the cost and performance anti-patterns that dominate warehouse bills - SELECT *, full-table scans, non-sargable predicates, Cartesian joins, the NOT IN NULL trap, and 15 more. It scores warehouse query health 0-100 (A-F) and outputs a prioritized cost-reduction plan, each finding with a why, a concrete fix, and an estimated savings. The engine splits a SQL script into statements (honoring quotes and comments), runs 20 rules over each statement, scores health 0-100 weighted by severity (critical 25, high 12, medium 5, low 1), and returns a prioritized cost-reduction plan.
When to use - and when NOT to
Use sql-sentinel when you write or review a query for BigQuery, Snowflake, Redshift, Postgres, or Spark SQL; when you ask "why is this query so slow?" or "why is my warehouse bill so high?"; when you are about to promote a dashboard query or dbt model to production; when a data engineer wants a second pair of eyes before a code review or a cost-optimization sweep; or when a team is running a "reduce cloud spend" or FinOps initiative.
Do NOT use this as a substitute for query-plan analysis or billing data. This is a static analyzer that finds anti-patterns in the text of SQL; it does not read query plans, row counts, or billing. A flagged query on a 100-row table is cheap; the same query on a billion-row table is the problem the rule exists to prevent.
Inputs and outputs
You provide a SQL script as a file path or string. You receive a report object containing a health score (0-100), a letter grade (A-F), and a prioritized plan - an array of findings sorted by severity, each with a rule ID, severity level, explanation of why it costs money, and a concrete fix.
git clone https://github.com/takeaseatventure/sql-sentinel.git
cd sql-sentinel
git checkout <reviewed-commit-or-tag>
node scripts/sql-sentinel.js path/to/query.sql
Programmatic usage:
const { auditSql } = require('./scripts/sql-sentinel');
const report = auditSql(yourSqlString, { dialect: 'bigquery' });
console.log(report.healthScore); // 0-100
console.log(report.grade); // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
console.log(report.prioritizedPlan); // array, worst findings first
For example, a messy dashboard query with comma-joins, SELECT *, and NOT IN scores 17/100 (grade F) and flags 7 findings. A clean, sargable query scores 90+/100 (grade A) with no findings.
Integrations
Works across BigQuery, Snowflake, Redshift, and Postgres. Built for analytics engineers using dbt and Looker, and data platform teams running FinOps or "reduce cloud spend" initiatives. Zero dependencies, MIT licensed.
Who it's for
Analytics engineers (dbt, Looker), data platform teams running FinOps or "reduce cloud spend" initiatives, and anyone reviewing a SQL pull request before it hits production. The 20-rule set (ruleset v1.0.0) catches critical issues like CROSS JOIN and comma-joins, high-severity patterns like SELECT * and leading-wildcard LIKE, medium-severity issues like SELECT DISTINCT and scalar subqueries, and low-severity style problems. Run the test suite to verify each rule fires on real SQL: cd scripts && node test.js (26 tests, zero dependencies). It does not execute SQL - safe to run on any .sql file.
Source README
sql-sentinel
Overview
A static-analysis skill that audits SQL for the cost & performance anti-patterns that dominate warehouse bills - SELECT *, full-table scans, non-sargable predicates, Cartesian joins, the NOT IN NULL trap, and 15 more. It scores warehouse query health 0-100 (A-F) and outputs a prioritized cost-reduction plan, each finding with a why, a concrete fix, and an estimated savings.
Built for analytics engineers (dbt, Looker), data platform teams running FinOps / "reduce cloud spend" initiatives, and anyone reviewing a SQL pull request before it hits production. Works across BigQuery, Snowflake, Redshift, and Postgres. Zero dependencies, MIT licensed.
The executable engine and full rule set live in the source repository: https://github.com/takeaseatventure/sql-sentinel. Treat that repository as third-party executable code.
When to Use This Skill
- A user writes or reviews a query for BigQuery, Snowflake, Redshift, Postgres, or Spark SQL.
- A user asks "why is this query so slow?" or "why is my warehouse bill so high?"
- A user is about to promote a dashboard query or dbt model to production.
- A data engineer wants a second pair of eyes before a code review or a cost-optimization sweep.
- A team is running a "reduce cloud spend" or FinOps initiative.
How It Works
The engine splits a SQL script into statements (honoring quotes and comments), runs 20 rules over each statement, scores health 0-100 weighted by severity (critical 25, high 12, medium 5, low 1), and returns a prioritized cost-reduction plan.
Step 1: Run the audit
Install or clone the source repository only after choosing a reviewed commit, tag, or release to trust. Do not run code from a mutable default branch just because this skill links to it:
git clone https://github.com/takeaseatventure/sql-sentinel.git
cd sql-sentinel
git checkout <reviewed-commit-or-tag>
node scripts/sql-sentinel.js path/to/query.sql
Or programmatically:
const { auditSql } = require('./scripts/sql-sentinel');
const report = auditSql(yourSqlString, { dialect: 'bigquery' });
console.log(report.healthScore); // 0-100
console.log(report.grade); // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
console.log(report.prioritizedPlan); // array, worst findings first
Step 2: Read the prioritized plan
The output leads with critical findings (Cartesian joins, mass DELETE) and descends to low-severity style issues. Each finding explains why it costs money and how to fix it.
Examples
Example 1: A messy dashboard query
SELECT DISTINCT *
FROM user_events, raw_logs
WHERE LOWER(event_name) LIKE '%signup%'
AND user_id NOT IN (SELECT id FROM deleted_users)
ORDER BY created_at;
The audit scores this 17/100 (grade F) and flags 7 findings:
- CRITICAL: comma-join produces a Cartesian product (can turn a $0.02 query into a $200 query)
- HIGH:
SELECT *forces full column scan (30-90% wasted bytes on wide tables) - HIGH: leading-wildcard
LIKE '%signup%'defeats indexes - HIGH:
LOWER(event_name)defeats indexes (non-sargable) - HIGH:
NOT IN (SELECT ...)- NULL semantics hazard - MEDIUM:
SELECT DISTINCTdedup cost - MEDIUM:
ORDER BYwithoutLIMITsorts the full result
Example 2: A clean, sargable query
-- This scores 90+/100 (grade A) — no findings
SELECT id, email, created_at
FROM users
WHERE created_at >= TIMESTAMP '2026-01-01'
AND created_at < TIMESTAMP '2026-02-01'
ORDER BY id
LIMIT 100;
The 20 rules (ruleset v1.0.0)
| Rule | Severity | Catches |
|---|---|---|
| SQL001 | high | SELECT * full column scan |
| SQL002 | critical | No WHERE → full table scan |
| SQL003 | high | LIKE '%term' non-sargable |
| SQL004 | high | Function on column kills index |
| SQL005 | critical | CROSS JOIN / comma-join |
| SQL006 | medium | SELECT DISTINCT dedup cost |
| SQL007 | medium | ORDER BY without LIMIT |
| SQL008 | high | NOT IN (SELECT ...) NULL trap |
| SQL009 | medium | Implicit type cast |
| SQL010 | low | Many ORs (use IN/UNION) |
| SQL011 | medium | COUNT(DISTINCT) at scale (use HLL) |
| SQL012 | low | LIMIT without ORDER BY |
| SQL013 | medium | Scalar subquery in SELECT |
| SQL014 | medium | 5+ JOINs broadcast/spill risk |
| SQL015 | high | Fact table, no partition filter |
| SQL017 | low | String concat in SELECT |
| SQL018 | medium | Window OVER () no PARTITION |
| SQL020 | critical | DELETE/UPDATE without WHERE |
| SQL021 | low | SELECT * in EXISTS/IN |
| SQL022 | medium | UNION vs UNION ALL |
Run the test suite to verify each rule fires on real SQL:
cd scripts && node test.js # 26 tests, zero dependencies
Limitations
- This is a static analyzer. It finds anti-patterns in the text of SQL; it does not read query plans, row counts, or billing. A flagged query on a 100-row table is cheap; the same query on a billion-row table is the problem the rule exists to prevent.
- The fact-table heuristic (SQL015) keys off table names (
*_events,*_log) and is advisory, not definitive. - It does not execute SQL - safe to run on any
.sqlfile.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.