sql-query-optimizer / README.md
Param20h's picture
Upload folder using huggingface_hub
2541228 verified
---
title: SQL Query Optimizer Environment Server
emoji: 🐳
colorFrom: blue
colorTo: indigo
sdk: docker
pinned: false
app_port: 7860
base_path: /web
tags:
- openenv
---
# SQL Query Optimizer β€” OpenEnv Environment
An **OpenEnv-compliant** environment where AI agents learn to review, rewrite, and optimise SQL queries across three real-world failure patterns.
> **HF Spaces**: [param20h/sql-query-optimizer](https://huggingface.co/spaces/param20h/sql-query-optimizer)
---
## Environment Description
Real-world SQL anti-patterns cost companies millions in infrastructure. This environment teaches agents to identify and fix them through a reward-shaped episode loop. Each episode presents the agent with a broken or unoptimised query alongside schema context; the agent iteratively rewrites it until done or max steps are reached.
**Why this domain?**
- Used by data engineers and DBAs every day
- Deterministically gradeable (no ambiguous LLM judging)
- Natural difficulty progression from syntax errors to multi-factor optimisation
---
## Observation Space
| Field | Type | Description |
|---|---|---|
| `task_id` | `int` | Task number (1–3) |
| `task_name` | `str` | Slug identifier |
| `task_description` | `str` | What the agent must accomplish |
| `query` | `str` | The SQL to fix |
| `schema_context` | `str` | Relevant DDL / table definitions |
| `hint` | `str \| null` | Optional hint (tasks 1 & 2 only) |
| `step_number` | `int` | Current step (0-indexed) |
| `max_steps` | `int` | Steps allowed per episode |
| `done` | `bool` | Whether episode has ended |
---
## Action Space
| Field | Type | Description |
|---|---|---|
| `rewritten_query` | `str` | The agent's improved SQL |
| `explanation` | `str` | Brief description of changes made |
| `is_done` | `bool` | `true` when the agent believes the query is fully fixed |
---
## Reward Design
The reward is **shaped** (not sparse) β€” the agent receives signal every step:
| Component | Value | Trigger |
|---|---|---|
| Delta reward | +0.0–0.50 Γ— Ξ”grader | Grader score improves |
| Completion bonus | +0.50 | `is_done=True` and grader β‰₯ 0.80 |
| Partial completion | +grader Γ— 0.30 | `is_done=True` (always) |
| Step penalty | βˆ’0.02 / step | After halfway point, if not done |
| Invalid penalty | βˆ’0.10 | Empty or unparseable query |
Final `score` per step is clamped to `[0.0, 1.0]`.
---
## Tasks
### Task 1 β€” `fix-broken-join` (Easy)
The query uses a comma-separated cross-join (`FROM orders, customers`) without any join condition, causing a Cartesian product. The agent must rewrite with `INNER JOIN … ON o.customer_id = c.customer_id`.
**Max steps**: 3 | **Grader**: checks JOIN keyword + ON clause with correct key
### Task 2 β€” `eliminate-n-plus-one` (Medium)
A correlated scalar subquery in the `SELECT` list executes once per row (N+1 problem). The agent must collapse it into a single `LEFT JOIN departments ON e.dept_id = d.dept_id`.
**Max steps**: 4 | **Grader**: checks subquery removal + JOIN on dept_id
### Task 3 β€” `full-optimization` (Hard)
Four independent issues to fix:
1. Remove redundant `DISTINCT` (PK join makes it unnecessary)
2. Replace `SELECT *` with explicit columns
3. Replace `CAST(price AS VARCHAR) LIKE '1%'` β†’ `price >= 100 AND price < 200` (sargable)
4. Add an index hint comment for `(category, price)`
**Max steps**: 5 | **Grader**: 4 Γ— 0.25 sub-criteria, fully independent
---
## API Endpoints
| Method | Path | Description |
|---|---|---|
| `GET` | `/` | Health check |
| `POST` | `/reset` | Start episode `{ "task_id": 1 }` |
| `POST` | `/step` | Submit action `{ "rewritten_query": "...", "explanation": "...", "is_done": true }` |
| `GET` | `/state` | Current internal state |
| `GET` | `/tasks` | All tasks + action schema |
| `GET` | `/grader` | Grader score for current episode |
| `POST` | `/baseline` | Run baseline inference (requires `OPENAI_API_KEY`) |
Interactive docs: `http://localhost:7860/docs`
---
## Setup & Usage
### Prerequisites
- Python 3.10+
- Docker
- `API_BASE_URL` (OpenAI-compatible endpoint for inference)
- `MODEL_NAME` (model identifier for inference)
- `HF_TOKEN` (API key / bearer token for inference)
### Local (Python)
```bash
pip install -r requirements.txt
uvicorn server:app --host 0.0.0.0 --port 7860 --reload
```
### Local (Docker)
```bash
docker build -t sql-optimizer-env .
docker run -p 7860:7860 -e OPENAI_API_KEY=sk-... sql-optimizer-env
```
### Baseline Inference
```bash
$env:API_BASE_URL="https://api.openai.com/v1"
$env:MODEL_NAME="gpt-4o-mini"
$env:HF_TOKEN="hf_or_openai_api_key_here"
python inference.py
```
### OpenEnv Validation
```bash
pip install openenv-core
openenv validate
```
### Deploy to HF Spaces
```bash
pip install huggingface_hub
huggingface-cli login
openenv push --repo-id your-username/sql-query-optimizer
```
### Environment Configuration
Define these variables before running inference or `/baseline`:
```powershell
$env:API_BASE_URL = "https://api.openai.com/v1"
$env:MODEL_NAME = "gpt-4o-mini"
$env:HF_TOKEN = "your_api_key"
```
---
## Baseline Scores
Measured with `gpt-4o-mini` at `temperature=0`, single-pass:
| Task | Name | Difficulty | Grader Score |
|---|---|---|---|
| 1 | fix-broken-join | Easy | 0.86 |
| 2 | eliminate-n-plus-one | Medium | 0.72 |
| 3 | full-optimization | Hard | 0.50 |
| β€” | **Average** | β€” | **0.69** |
> Scores are reproducible: same model, same temperature, same grader β†’ same output.
---
## Project Structure
```
metaXscaler/
β”œβ”€β”€ env/
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ environment.py # reset(), step(), state()
β”‚ β”œβ”€β”€ models.py # Observation, Action, Reward (Pydantic)
β”‚ β”œβ”€β”€ tasks.py # Task definitions + graders
β”‚ └── reward.py # Shaped reward function
β”œβ”€β”€ server.py # FastAPI app
β”œβ”€β”€ baseline.py # Baseline inference script
β”œβ”€β”€ openenv.yaml # OpenEnv spec metadata
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ requirements.txt
└── README.md
```
---
## License
MIT