add brain

This commit is contained in:
2026-03-12 15:17:52 +07:00
parent fd9f558fa1
commit e7821a7a9d
355 changed files with 93784 additions and 24 deletions

View File

@@ -0,0 +1,66 @@
---
title: EXPLAIN Plan Analysis
description: EXPLAIN output guide
tags: mysql, explain, query-plan, performance, indexes
---
# EXPLAIN Analysis
```sql
EXPLAIN SELECT ...; -- estimated plan
EXPLAIN FORMAT=JSON SELECT ...; -- detailed with cost estimates
EXPLAIN FORMAT=TREE SELECT ...; -- tree format (8.0+)
EXPLAIN ANALYZE SELECT ...; -- actual execution (8.0.18+, runs the query, uses TREE format)
```
## Access Types (Best → Worst)
`system``const``eq_ref``ref``range``index` (full index scan) → `ALL` (full table scan)
Target `ref` or better. `ALL` on >1000 rows almost always needs an index.
## Key Extra Flags
| Flag | Meaning | Action |
|---|---|---|
| `Using index` | Covering index (optimal) | None |
| `Using filesort` | Sort not via index | Index the ORDER BY columns |
| `Using temporary` | Temp table for GROUP BY | Index the grouped columns |
| `Using join buffer` | No index on join column | Add index on join column |
| `Using index condition` | ICP — engine filters at index level | Generally good |
## key_len — How Much of Composite Index Is Used
Byte sizes: `TINYINT`=1, `INT`=4, `BIGINT`=8, `DATE`=3, `DATETIME`=5, `VARCHAR(N)` utf8mb4: N×4+1 (or +2 when N×4>255). Add 1 byte per nullable column.
```sql
-- Index: (status TINYINT, created_at DATETIME)
-- key_len=2 → only status (1+1 null). key_len=8 → both columns used.
```
## rows vs filtered
- `rows`: estimated rows examined after index access (before additional WHERE filtering)
- `filtered`: percent of examined rows expected to pass the full WHERE conditions
- Rough estimate of rows that satisfy the query: `rows × filtered / 100`
- Low `filtered` often means additional (non-indexed) predicates are filtering out lots of rows
## Join Order
Row order in EXPLAIN output reflects execution order: the first row is typically the first table read, and subsequent rows are joined in order. Use this to spot suboptimal join ordering (e.g., starting with a large table when a selective table could drive the join).
## EXPLAIN ANALYZE
**Availability:** MySQL 8.0.18+
**Important:** `EXPLAIN ANALYZE` actually executes the query (it does not return the result rows). It uses `FORMAT=TREE` automatically.
**Metrics (TREE output):**
- `actual time`: milliseconds (startup → end)
- `rows`: actual rows produced by that iterator
- `loops`: number of times the iterator ran
Compare estimated vs actual to find optimizer misestimates. Large discrepancies often improve after refreshing statistics:
```sql
ANALYZE TABLE your_table;
```
**Limitations / pitfalls:**
- Adds instrumentation overhead (measurements are not perfectly "free")
- Cost units (arbitrary) and time (ms) are different; don't compare them directly
- Results reflect real execution, including buffer pool/cache effects (warm cache can hide I/O problems)