performance

package
v1.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package performance provides linter rules for detecting SQL anti-patterns that cause poor query performance, full table scans, or N+1 problems.

Rules:

  • L016: SELECT * (fetches all columns)
  • L017: Missing WHERE on SELECT (full scan risk)
  • L018: Leading wildcard LIKE (prevents index use)
  • L019: NOT IN with subquery (NULL risk)
  • L020: Correlated subquery in SELECT list (N+1)
  • L021: OR instead of IN (multiple equality conditions)
  • L022: Function on indexed column in WHERE
  • L023: Implicit cross join (comma-separated tables)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FunctionOnColumnRule

type FunctionOnColumnRule struct{ linter.BaseRule }

FunctionOnColumnRule (L022) detects function calls wrapped around column references in WHERE clauses (e.g., YEAR(created_at) = 2024). Wrapping a column in a function prevents the query planner from using indexes.

func NewFunctionOnColumnRule

func NewFunctionOnColumnRule() *FunctionOnColumnRule

NewFunctionOnColumnRule creates a new L022 rule instance.

func (*FunctionOnColumnRule) Check

Check walks the AST looking for function-on-column patterns in WHERE clauses.

func (*FunctionOnColumnRule) Fix

func (r *FunctionOnColumnRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: rewriting function-on-column requires domain knowledge.

type ImplicitCrossJoinRule

type ImplicitCrossJoinRule struct{ linter.BaseRule }

ImplicitCrossJoinRule (L023) flags queries that reference multiple tables in the FROM clause without explicit JOIN syntax. Comma-separated tables create an implicit cross join (Cartesian product) which is almost always unintentional and produces an explosive result set.

func NewImplicitCrossJoinRule

func NewImplicitCrossJoinRule() *ImplicitCrossJoinRule

NewImplicitCrossJoinRule creates a new L023 rule instance.

func (*ImplicitCrossJoinRule) Check

Check walks the AST for SELECT statements with multiple FROM tables and no JOINs at any nesting level. Implicit cross joins buried in subqueries or CTE bodies are just as dangerous as top-level ones.

func (*ImplicitCrossJoinRule) Fix

func (r *ImplicitCrossJoinRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: converting implicit cross join to explicit JOIN requires intent.

type LeadingWildcardRule

type LeadingWildcardRule struct{ linter.BaseRule }

LeadingWildcardRule (L018) flags LIKE patterns with a leading wildcard (% or _). A leading wildcard forces a full table scan — it cannot use a B-tree index.

func NewLeadingWildcardRule

func NewLeadingWildcardRule() *LeadingWildcardRule

NewLeadingWildcardRule creates a new L018 rule instance.

func (*LeadingWildcardRule) Check

Check walks the AST looking for LIKE patterns with leading wildcards.

func (*LeadingWildcardRule) Fix

func (r *LeadingWildcardRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: leading wildcard removal requires schema/query redesign.

type MissingWhereRule

type MissingWhereRule struct{ linter.BaseRule }

MissingWhereRule (L017) flags SELECT statements with no WHERE clause and no LIMIT on queries that reference at least one table — indicating a potential full table scan.

func NewMissingWhereRule

func NewMissingWhereRule() *MissingWhereRule

NewMissingWhereRule creates a new L017 rule instance.

func (*MissingWhereRule) Check

func (r *MissingWhereRule) Check(ctx *linter.Context) ([]linter.Violation, error)

Check walks the AST for SELECT statements without WHERE/LIMIT on tables. Fires at any nesting level — subqueries and CTE bodies that scan a table without filtering are just as expensive as top-level scans.

func (*MissingWhereRule) Fix

func (r *MissingWhereRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: adding WHERE/LIMIT requires understanding business logic.

type NotInWithNullRule

type NotInWithNullRule struct{ linter.BaseRule }

NotInWithNullRule (L019) flags NOT IN (subquery) patterns. If the subquery returns any NULL value, the entire NOT IN expression evaluates to UNKNOWN (never true), silently returning zero rows — a common SQL trap.

func NewNotInWithNullRule

func NewNotInWithNullRule() *NotInWithNullRule

NewNotInWithNullRule creates a new L019 rule instance.

func (*NotInWithNullRule) Check

func (r *NotInWithNullRule) Check(ctx *linter.Context) ([]linter.Violation, error)

Check walks the AST looking for NOT IN (subquery) patterns.

func (*NotInWithNullRule) Fix

func (r *NotInWithNullRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: changing NOT IN to NOT EXISTS requires semantic understanding.

type OrInsteadOfInRule

type OrInsteadOfInRule struct{ linter.BaseRule }

OrInsteadOfInRule (L021) detects repeated equality conditions on the same column joined by OR (e.g., col = A OR col = B OR col = C) and suggests using IN instead. Multiple ORs on the same column can prevent index use and are harder to read.

func NewOrInsteadOfInRule

func NewOrInsteadOfInRule() *OrInsteadOfInRule

NewOrInsteadOfInRule creates a new L021 rule instance.

func (*OrInsteadOfInRule) Check

func (r *OrInsteadOfInRule) Check(ctx *linter.Context) ([]linter.Violation, error)

Check walks the AST looking for OR-based equality chains on the same column.

func (*OrInsteadOfInRule) Fix

func (r *OrInsteadOfInRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: refactoring OR to IN requires careful SQL manipulation.

type SelectStarRule

type SelectStarRule struct{ linter.BaseRule }

SelectStarRule (L016) flags SELECT * usage. SELECT * fetches all columns, preventing index-only scans and over-fetching data.

func NewSelectStarRule

func NewSelectStarRule() *SelectStarRule

NewSelectStarRule creates a new L016 rule instance.

func (*SelectStarRule) Check

func (r *SelectStarRule) Check(ctx *linter.Context) ([]linter.Violation, error)

Check walks the AST for SELECT * usage at any nesting level (subqueries, CTEs, derived tables, set operations). Every SELECT statement encountered is checked for a bare "*" column reference.

func (*SelectStarRule) Fix

func (r *SelectStarRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: cannot auto-fix without schema knowledge.

type SubqueryInSelectRule

type SubqueryInSelectRule struct{ linter.BaseRule }

SubqueryInSelectRule (L020) flags correlated subqueries in the SELECT column list. A subquery in the SELECT list is executed once per row — this is the classic N+1 problem.

func NewSubqueryInSelectRule

func NewSubqueryInSelectRule() *SubqueryInSelectRule

NewSubqueryInSelectRule creates a new L020 rule instance.

func (*SubqueryInSelectRule) Check

Check walks the AST for subqueries used as SELECT column expressions at any nesting level (including nested SELECTs and CTE bodies). Every SELECT encountered has its column list examined for scalar subqueries.

func (*SubqueryInSelectRule) Fix

func (r *SubqueryInSelectRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is a no-op: refactoring N+1 requires schema/query redesign.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL