[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-mariadb-mariadb-query-optimization":3,"mdc-tuq0cj-key":34,"related-org-mariadb-mariadb-query-optimization":3768,"related-repo-mariadb-mariadb-query-optimization":3865},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":29,"sourceUrl":32,"mdContent":33},"mariadb-query-optimization","optimize MariaDB database queries","Best practices for query optimization in MariaDB — indexing strategies, EXPLAIN analysis, pagination, histogram statistics, and MariaDB-specific optimizer settings. Use when diagnosing slow queries, designing indexes, reviewing schema or query performance, or when queries involve large tables, pagination, GROUP BY, or ORDER BY. Also use when the user asks about MariaDB query performance, EXPLAIN output, or optimizer behavior.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},"mariadb","MariaDB","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmariadb.png",[12,16,17,20],{"name":13,"slug":14,"type":15},"Performance","performance","tag",{"name":9,"slug":8,"type":15},{"name":18,"slug":19,"type":15},"Database","database",{"name":21,"slug":22,"type":15},"SQL","sql",9,"https:\u002F\u002Fgithub.com\u002FMariaDB\u002Fskills","2026-07-13T06:14:12.656074",null,2,[],{"repoUrl":24,"stars":23,"forks":27,"topics":30,"description":31},[],"MariaDB skills for Claude Code and AI agents - because it is not MySQL","https:\u002F\u002Fgithub.com\u002FMariaDB\u002Fskills\u002Ftree\u002FHEAD\u002Fmariadb-query-optimization","---\nname: mariadb-query-optimization\ndescription: \"Best practices for query optimization in MariaDB — indexing strategies, EXPLAIN analysis, pagination, histogram statistics, and MariaDB-specific optimizer settings. Use when diagnosing slow queries, designing indexes, reviewing schema or query performance, or when queries involve large tables, pagination, GROUP BY, or ORDER BY. Also use when the user asks about MariaDB query performance, EXPLAIN output, or optimizer behavior.\"\n---\n\n# MariaDB Query Optimization\n\n*Last updated: 2026-06-05*\n\n> **Requires:** MariaDB 10.1+ for `ANALYZE` and histograms; optimizer improvements through **11.8 LTS** (GA May 2025) form the baseline below.\n>\n> **Default context:** Assume MariaDB **11.8 LTS** unless the user states another version. Features marked **12.x** may be suggested when relevant (including as upgrade options), but always state the minimum version — do not present them as available on 11.8.\n\n## What LLMs Get Wrong\n\n| Pattern | What to do instead |\n|---|---|\n| `SELECT * FROM table LIMIT 10 OFFSET 50000` | Use cursor-based pagination — `OFFSET` scans all skipped rows |\n| Blanket rule \"functions on indexed columns kill indexes\" | Outdated on MariaDB 11.1+\u002F11.3+ for many cases. `YEAR(col) = const` and `UPPER(col) = const` on case-insensitive columns can now use indexes — see [Functions on indexed columns](#functions-on-indexed-columns) below |\n| Adding an index to a low-cardinality column (boolean, status with 2-3 values) | Optimizer skips indexes with low selectivity and does a table scan anyway |\n| Not running `ANALYZE TABLE` after bulk inserts | Histogram statistics become stale; optimizer makes poor plan choices |\n| Composite index `(a, b, c)` used in `WHERE b = 1 AND c = 2` | Leftmost prefix rule: this skips `a`, so the index is not used |\n| `SELECT *` in queries with JOINs | Name only the columns needed — prevents accidentally blocking covering indexes |\n| `ALTER TABLE t ALTER INDEX idx INVISIBLE` to disable an index | That's MySQL syntax. MariaDB uses `IGNORED` — see [Ignored Indexes](#ignored-indexes-not-invisible) below |\n| Jump straight to `EXPLAIN` or indexes on a slow server | Enable [Performance Schema](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsystem-tables\u002Fperformance-schema\u002Fperformance-schema-overview) at **startup** first — it is **off by default** and cannot be turned on at runtime |\n| `SET GLOBAL performance_schema = ON` to enable monitoring | Performance Schema requires `performance_schema=ON` in `my.cnf` and a **server restart** |\n\n## Performance Schema (enable first)\n\nBefore `EXPLAIN`, indexes, or query rewrites, confirm the server can observe what queries are doing. MariaDB's [Performance Schema](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsystem-tables\u002Fperformance-schema\u002Fperformance-schema-overview) is the built-in monitoring layer (10.5+: ~80 tables in the `performance_schema` database).\n\n**Check status:**\n\n```sql\nSHOW VARIABLES LIKE 'performance_schema';\n```\n\n**Critical:** Performance Schema is **disabled by default** and **cannot be enabled at runtime**. If `OFF`, add to `my.cnf` and restart:\n\n```ini\n[mysqld]\nperformance_schema=ON\n```\n\n**After restart**, enable the consumers and instruments you need. Scope with `WHERE NAME LIKE '...'` rather than enabling everything blindly in production — see the overview doc:\n\n```sql\nUPDATE performance_schema.setup_consumers SET ENABLED = 'YES';\nUPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES';\n```\n\nUse `performance_schema` (waits, stages, statements, and related summary tables) to see where time goes; then use `EXPLAIN` and `ANALYZE` below to understand why the optimizer chose a plan. On **10.7.1+**, column comments help interpret tables:\n\n```sql\nSELECT column_name, column_comment\n  FROM information_schema.columns\n WHERE table_schema = 'performance_schema' AND table_name = 'events_statements_summary_by_digest';\n```\n\n## Reading EXPLAIN\n\nWith Performance Schema available when diagnosing production slowness, run `EXPLAIN` to inspect the optimizer's plan:\n\n```sql\nEXPLAIN SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC LIMIT 10;\n```\n\n**Red flags in the output:**\n\n| Field | Red flag | What it means |\n|---|---|---|\n| `type` | `ALL` | Full table scan — missing index or index not used |\n| `key` | `NULL` | No index used despite one existing — check for function on column or type mismatch |\n| `rows` | Very high number | Optimizer estimates scanning many rows |\n| `Extra` | `Using filesort` | Expensive sort not covered by an index |\n| `Extra` | `Using temporary` | Temp table created — often from `GROUP BY` or `DISTINCT` |\n| `Extra` | `Using index` | ✅ Good — covering index, no table row access needed |\n\n**`ANALYZE`** statement (MariaDB 10.1+) actually executes the query and shows real row counts vs. estimates — more reliable than `EXPLAIN` alone. Note: MariaDB uses `ANALYZE`, not `EXPLAIN ANALYZE`:\n\n```sql\nANALYZE SELECT * FROM orders WHERE customer_id = 42;\n```\n\n**Optimizer Trace** shows the optimizer's full decision process. Since MariaDB 12.1 the trace can include full table and view definitions (`optimizer_record_context` system variable). Since 13.0 it also includes the specific statistics (histograms, index stats) used for cardinality estimates — together they're powerful for diagnosing surprising `rows` estimates:\n\n```sql\nSET optimizer_trace = 'enabled=on';\nSELECT * FROM orders WHERE customer_id = 42;\nSELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\\G\nSET optimizer_trace = 'enabled=off';\n```\n\n## Indexing Rules\n\n### The Leftmost Prefix Rule\n\nFor a composite index `(a, b, c)`, MariaDB can use:\n- `WHERE a = 1` ✅\n- `WHERE a = 1 AND b = 2` ✅\n- `WHERE a = 1 AND b = 2 AND c = 3` ✅\n- `WHERE b = 2` ✗ — skips `a`, index not used\n- `WHERE a = 1 AND c = 3` — only `a` part is used\n\nPut the most selective equality conditions first, then range conditions last:\n```sql\n-- Query: WHERE status = 'active' AND created_at > '2025-01-01' ORDER BY created_at\nINDEX (status, created_at)  -- ✅ equality first, range last\nINDEX (created_at, status)  -- ✗ range first breaks the prefix for status\n```\n\n### Covering Indexes\n\nA covering index includes all columns needed by the query — no table row access needed (`Using index` in EXPLAIN):\n\n```sql\n-- Query fetches id, status, created_at for a customer\n-- Covering index includes all three:\nCREATE INDEX idx_customer_cover ON orders (customer_id, status, created_at);\n-- Now EXPLAIN shows: Extra = Using index\n```\n\n### When NOT to Add an Index\n\n- **Low-cardinality columns**: a `status` column with values `active`\u002F`inactive` affects 50% of rows — the optimizer prefers a table scan. Index useful only when combined with other high-selectivity columns.\n- **Small tables** (\u003C a few thousand rows): full scans are faster than index lookups for tiny tables.\n- **Write-heavy columns**: every index slows `INSERT`, `UPDATE`, `DELETE` — don't index columns that are rarely queried.\n\n### Ignored Indexes (not INVISIBLE)\n\nTo make the optimizer skip an index without dropping it — useful for testing whether an index is actually needed before removing it — MariaDB uses `IGNORED`, **not** MySQL's `INVISIBLE`:\n\n```sql\n-- ✅ MariaDB syntax (10.6+):\nALTER TABLE demo ALTER INDEX index_name IGNORED;\nALTER TABLE demo ALTER INDEX index_name NOT IGNORED;  -- re-enable\n\n-- ✗ MySQL syntax — fails on MariaDB:\nALTER TABLE demo ALTER INDEX index_name INVISIBLE;\n```\n\nThe index is still maintained on writes; it's just hidden from the optimizer. A primary key cannot be ignored. See [Ignored Indexes](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Foptimization-and-indexes\u002Fignored-indexes).\n\n### Functions on Indexed Columns\n\nThe classic rule \"any function on an indexed column disables the index\" is **outdated for MariaDB 11.1+ and 11.4 LTS**. The optimizer can now use indexes for a number of common function patterns:\n\n| Pattern | Works on the index? | Since |\n|---|---|---|\n| `WHERE YEAR(col) = 2025` | ✅ — sargable, picks the right range | 11.1+ (MDEV-8320) |\n| `WHERE DATE(col) \u003C= '2025-12-31'` | ✅ — sargable | 11.1+ (MDEV-8320) |\n| `WHERE UPPER(varchar_col) = '...'` on a case-insensitive collation (e.g. `utf8mb4_uca1400_ai_ci`) | ✅ — `sargable_casefold=ON` is the default | 11.3+ (MDEV-31496) |\n| `WHERE SUBSTR(col, 1, n) = 'abc'` | ✅ — leading-prefix `SUBSTR` is optimized | 11.8+ (MDEV-34911) |\n| `WHERE LOWER(case_sensitive_col) = '...'` | ✗ — index not used (collation isn't case-insensitive) | — |\n| `WHERE CAST(col AS UNSIGNED) = 1` or other type-changing transforms | ✗ — index not used | — |\n\nFor cases that the optimizer still can't sargabilize, the rewrite-to-range pattern remains valid:\n\n```sql\nWHERE created_at >= '2025-01-01' AND created_at \u003C '2026-01-01'\n```\n\nVerify with `EXPLAIN` rather than assuming: on 11.4+ many \"won't use the index\" rewrites are now no-ops. If `EXPLAIN` still shows `type=ALL` for a sargable pattern, check `@@optimizer_switch` for `sargable_casefold` and confirm the column's collation is `_ci`.\n\n### Functional Indexes: Use a Generated Column\n\nMySQL 8.0.13+ supports **functional key parts** — indexing an expression directly with a doubled-parenthesis syntax. MariaDB does **not** support this:\n\n```sql\n-- ✗ MySQL syntax — fails on MariaDB:\nCREATE INDEX idx_upper ON users ((UPPER(name)));\nALTER TABLE orders ADD INDEX ((total * quantity));\n```\n\nIn MariaDB, index a [generated (computed) column](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsql-statements\u002Fdata-definition\u002Fcreate\u002Fgenerated-columns) instead. A `VIRTUAL` column stores nothing and is computed on read; the index on it persists the expression's value, which is what gets searched:\n\n```sql\n-- ✅ MariaDB equivalent:\nALTER TABLE users\n  ADD COLUMN name_upper VARCHAR(255) AS (UPPER(name)) VIRTUAL,\n  ADD INDEX idx_name_upper (name_upper);\n\n-- Query the column the optimizer can resolve directly,\n-- or rely on virtual-column optimizer support (11.8+) for WHERE UPPER(name) = ...\nSELECT * FROM users WHERE name_upper = 'ALICE';\n```\n\nNote that for many simple cases (`YEAR(col)`, `UPPER(col)` on `_ci` collations) MariaDB 11.1+ no longer needs an indexed expression at all — see the table above. Reach for a generated column when the expression isn't sargable on its own.\n\n## Pagination: Cursor-Based Instead of OFFSET\n\n`OFFSET` is a hidden performance trap. `LIMIT 10 OFFSET 50000` scans and discards 50,000 rows on every page load.\n\n```sql\n-- ✗ Slow — scans 50,000 rows to skip them:\nSELECT id, title FROM posts ORDER BY id DESC LIMIT 10 OFFSET 50000;\n\n-- ✅ Fast — index seek directly to the cursor position:\n-- First page:\nSELECT id, title FROM posts ORDER BY id DESC LIMIT 10;\n\n-- Next page (pass last id from previous result as $last_id):\nSELECT id, title FROM posts WHERE id \u003C $last_id ORDER BY id DESC LIMIT 10;\n```\n\nFor filtered queries, include the filter column in the index alongside id:\n\n```sql\n-- Query: WHERE category = 'news' ORDER BY id DESC\nCREATE INDEX idx_cat_id ON posts (category, id);\n-- Cursor query:\nSELECT id, title FROM posts WHERE category = 'news' AND id \u003C $last_id ORDER BY id DESC LIMIT 10;\n```\n\nTo detect whether another page exists, fetch `LIMIT 11` and check if the 11th row appears.\n\n## Histogram Statistics\n\nHistograms let the optimizer understand data distribution on non-indexed columns — critical for query plan quality on complex queries. Without them, the optimizer assumes uniform distribution and can choose wrong join orders.\n\n```sql\n-- Collect histograms for a table (requires a full scan — run during low traffic):\nANALYZE TABLE orders;\n\n-- Verify histograms were collected:\nSELECT * FROM mysql.column_stats WHERE table_name = 'orders';\n```\n\n**When to run `ANALYZE TABLE`:**\n- After bulk inserts or large data changes\n- When `EXPLAIN` shows unexpectedly high `rows` estimates\n- After initially creating a table and loading data\n\n**Tune histogram granularity** for tables with highly skewed data distributions:\n```sql\nSET histogram_size = 100;  -- default is 0 (disabled) in older versions, 254 in 10.4.3+\nANALYZE TABLE orders;\n```\n\nHistograms are collected per-column automatically when using `ANALYZE TABLE` with `histogram_size > 0`. They are stored in `mysql.column_stats` and consulted when `optimizer_use_condition_selectivity >= 4` (default in 10.4.1+).\n\n## MariaDB Optimizer Switches\n\nMariaDB's optimizer has more tunable flags than MySQL. The most useful for developers:\n\n```sql\n-- See current settings:\nSELECT @@optimizer_switch\\G\n\n-- Disable a specific optimization for a session (useful for debugging):\nSET optimizer_switch = 'derived_merge=off';\n\n-- Re-enable:\nSET optimizer_switch = 'derived_merge=on';\n```\n\n**Most impactful flags:**\n\n| Flag | Default | Effect |\n|---|---|---|\n| `derived_merge` | on | Merges derived tables into outer query — usually faster |\n| `semijoin` | on | Optimizes `IN`\u002F`EXISTS` subqueries — disable to debug unexpected plans |\n| `subquery_cache` | on | Caches correlated subquery results — big win for repeated subqueries |\n| `rowid_filter` | on | Pre-filters rowids before fetching rows — helps range queries |\n| `mrr` | off | Multi-Range Read — enable for large range scans on spinning disks |\n\nTurn flags off one at a time to isolate which optimization is causing a bad plan, then report via JIRA if a default setting produces a worse plan than the alternative.\n\n### Optimizer Improvements in the 10.7–10.11 LTS Window\n\nThe 10.11 LTS line bundles features that arrived in the 10.7–10.10 short-term releases:\n\n- **JSON-format histograms** (10.8+, MDEV-21130, MDEV-26519) — histogram statistics are stored in JSON and are more precise than the older binary format. Just running `ANALYZE TABLE` on 10.8+ gives the optimizer better cardinality estimates.\n- **Descending indexes** (10.8+, MDEV-13756) — `CREATE INDEX idx ON t (a ASC, b DESC)` is supported; useful for composite `ORDER BY a, b DESC` patterns and for `MIN()`\u002F`MAX()` on descending indexes.\n- **`SHOW ANALYZE [FORMAT=JSON]`** (10.9+, MDEV-27021) — get the optimizer plan and runtime stats for a query running in another connection without intrusion. `EXPLAIN FOR CONNECTION` syntax also supported (MDEV-10000).\n- **Improved optimization for joins with many `eq_ref` tables** (10.10+, MDEV-28852, MDEV-26278) — large star-schema-style joins plan dramatically better.\n- **`ANALYZE FORMAT=JSON` reports time spent in the optimizer itself** (10.11+, MDEV-28926) — separates planning time from execution time.\n\n### Optimizer Improvements in 11.4 LTS\n\nThe 11.4 LTS line continues the overhaul:\n\n- **New cost-based cost model** (11.0+) — replaces the older rule-based heuristics with a tuned model aware of SSDs and per-engine characteristics. `EXPLAIN` and join-order choices in 10.6 vs. 11.4 can differ noticeably on the same query. If you have manual `optimizer_adjust_secondary_key_costs` settings from 10.x, remove them — they're no-ops on 11.4+.\n- **Semi-join optimization for single-table `UPDATE`\u002F`DELETE`** (11.1+, MDEV-7487) — subqueries inside `UPDATE`\u002F`DELETE` can now use the same subquery rewrites that `SELECT` uses (materialization, semi-join, etc.). Often a large speedup, no rewrite needed.\n- **Sargable `DATE`\u002F`YEAR` comparisons against constants** (11.1+, MDEV-8320) — see [Functions on Indexed Columns](#functions-on-indexed-columns) above.\n- **Sargable case-folding** (11.3+, MDEV-31496, `sargable_casefold` on by default) — `UCASE`\u002F`LCASE`\u002F`UPPER`\u002F`LOWER` on a column with a case-insensitive collation can use the index.\n\n### Optimizer Improvements in 11.5–11.8 LTS\n\nThese are part of the current LTS baseline — useful for understanding what the optimizer can do today:\n\n- **Index Condition Pushdown on partitioned tables** (11.5+, MDEV-12404) — previously partitioned tables couldn't use ICP; now they do, often a large speedup on partitioned schemas\n- **`ANALYZE` shows selectivity of pushed index condition** (11.5+, MDEV-18478) — useful when diagnosing whether ICP is helping\n- **Charset Narrowing Optimization on by default** (11.8+, MDEV-34380) — eliminates unnecessary character set conversions in WHERE clauses\n- **`SUBSTR(col, 1, n) = const_str` optimization** (11.8+, MDEV-34911) — the optimizer can now use a column index even when the condition is a leading-prefix `SUBSTR`\n- **Virtual column support in the optimizer** (11.8+, MDEV-35616) — see [Virtual Column Support in the Optimizer](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fvirtual-column-support-in-the-optimizer); previously, virtual columns were largely invisible to the optimizer\n- **Cost-based subquery strategy for single-table `UPDATE`\u002F`DELETE`** (11.8+, MDEV-25008) — the optimizer now picks between subquery strategies by cost\n\n### Optimizer Improvements in MariaDB 12.x\n\nSeveral further limitations were lifted in the 12.x rolling releases:\n\n- **Rowid filtering on reverse-ordered scans** (12.0+) — previously `ORDER BY ... DESC` queries couldn't benefit from rowid filtering; now they can\n- **Index Condition Pushdown on reverse-ordered scans** (12.0+) — same fix for ICP\n- **Loose Index Scan (\"Use index for group-by\") works with `DESC` key parts** (12.0+) — previously required `ASC` indexes\n- **GROUP BY \u002F ORDER BY can use indexes on virtual columns** (12.1+)\n- **Reorderable LEFT JOIN optimization** (12.3+) — the optimizer can now reorder more `LEFT JOIN` combinations\n- **Distinct GROUP BY column inference** (12.2+) — derived tables with `GROUP BY` are recognized as having distinct group keys, enabling more optimizations downstream\n\nIf you target the 11.8 LTS baseline and see a plan that looks needlessly slow on a reverse-ordered or virtual-column query, it may be one of these — verify by running the same query on a 12.x version.\n\n## Optimizer Hints\n\nMariaDB 12.0 introduced a comprehensive MySQL-8-style optimizer hints framework (MDEV-35504), with additional hints added through 12.1 and 12.2. Hints go in a `\u002F*+ ... *\u002F` comment right after `SELECT` and override the optimizer for one query without changing session settings:\n\n```sql\nSELECT \u002F*+ JOIN_ORDER(o, c) *\u002F *\nFROM orders o JOIN customers c ON c.id = o.customer_id;\n```\n\n**Available hints:**\n\n| Hint | Since | Purpose |\n|---|---|---|\n| `QB_NAME(name)` | 12.0 | Name a query block so other hints can target it from outside |\n| `JOIN_FIXED_ORDER` \u002F `JOIN_ORDER(t1, t2, ...)` | 12.0 | Force a join order (`JOIN_FIXED_ORDER` is similar to `STRAIGHT_JOIN`) |\n| `JOIN_PREFIX(t1, ...)` \u002F `JOIN_SUFFIX(t1, ...)` | 12.0 | Force specific tables to be first or last in the join order |\n| `MAX_EXECUTION_TIME(ms)` | 12.0 | Abort the query if it runs longer than the timeout |\n| `[NO_]MRR` \u002F `[NO_]BKA` \u002F `[NO_]BNL` | 12.0 | Toggle Multi-Range Read, Batched Key Access, Block Nested Loop |\n| `[NO_]ICP` | 12.0 | Toggle Index Condition Pushdown |\n| `[NO_]RANGE_OPTIMIZATION` | 12.0 | Toggle range optimizer |\n| `SEMIJOIN(strategy, ...)` \u002F `SUBQUERY(strategy)` | 12.0 | Pick subquery rewrite strategy |\n| `[NO_]INDEX(t idx, ...)` \u002F `[NO_]JOIN_INDEX` \u002F `[NO_]GROUP_INDEX` \u002F `[NO_]ORDER_INDEX` | 12.1 | Force \u002F forbid specific index usage by purpose |\n| `[NO_]SPLIT_MATERIALIZED` \u002F `[NO_]DERIVED_CONDITION_PUSHDOWN` \u002F `[NO_]MERGE` | 12.1 | Control subquery \u002F derived-table optimizations |\n| `[NO_]ROWID_FILTER` \u002F `[NO_]INDEX_MERGE` | 12.2 | Toggle rowid filtering and index merge |\n\n**`QB_NAME()` example** — name a subquery so an outer hint can target it:\n\n```sql\nSELECT \u002F*+ NO_MERGE(@sub) *\u002F *\nFROM (\n    SELECT \u002F*+ QB_NAME(sub) *\u002F customer_id, COUNT(*) AS n\n    FROM orders\n    GROUP BY customer_id\n) t\nWHERE n > 10;\n```\n\nHints are more targeted than `SET optimizer_switch` because they apply only to the query they're in, not the whole session.\n\n## Bounding Expensive Queries: LIMIT ROWS EXAMINED\n\n`LIMIT ROWS EXAMINED` is a **MariaDB-specific** extension (since 5.5.21) with no MySQL equivalent. It caps how many rows a `SELECT` may examine, terminating execution early once the cap is hit — a safety valve against runaway scans on unbounded or ad-hoc queries:\n\n```sql\n-- Up to 10 result rows, but stop after examining 10,000 rows:\nSELECT * FROM t1, t2 LIMIT 10 ROWS EXAMINED 10000;\n\n-- The cap can be used on its own:\nSELECT * FROM big_table WHERE status = 'x' LIMIT ROWS EXAMINED 50000;\n```\n\nWhen the cap is reached the query returns a **partial result set** plus a warning — so it is a guard rail, not a way to get correct-but-faster answers. `SELECT` only; it is a syntax error on `UPDATE`\u002F`DELETE`. For a time-based bound instead, use the `MAX_EXECUTION_TIME(ms)` optimizer hint (12.0+) above. See [LIMIT ROWS EXAMINED](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Flimit-rows-examined).\n\n## Quick Wins Checklist\n\nBefore adding indexes or rewriting queries, check these first:\n\n1. Confirm `performance_schema=ON` at startup (restart required if off) — [Performance Schema Overview](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsystem-tables\u002Fperformance-schema\u002Fperformance-schema-overview)\n2. `EXPLAIN` the slow query — confirm where the time actually is\n3. `ANALYZE TABLE` — stale statistics cause bad plans\n4. Check for functions on indexed columns in `WHERE` — note many cases are now sargable on 11.4+ (`YEAR()`, `DATE()`, `UPPER()` on `_ci` collations)\n5. Check for `OFFSET` in pagination queries\n6. Verify composite index column order matches query predicates (leftmost prefix)\n7. Check `EXPLAIN` Extra column for `Using filesort` or `Using temporary` — these often point to a missing or misordered index\n\n## Sources\n\n- [Query Optimizations — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations)\n- [Performance Schema Overview — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsystem-tables\u002Fperformance-schema\u002Fperformance-schema-overview)\n- [EXPLAIN — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsql-statements\u002Fadministrative-sql-statements\u002Fanalyze-and-explain-statements\u002Fexplain)\n- [optimizer_switch — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Foptimizer-switch)\n- [Getting Started with Indexes — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fmariadb-quickstart-guides\u002Fmariadb-indexes-guide)\n- [Building the Best Index for a Given SELECT — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Foptimization-and-indexes\u002Fbuilding-the-best-index-for-a-given-select)\n- [Histogram-Based Statistics — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fstatistics-for-optimizing-queries\u002Fhistogram-based-statistics)\n- [Pagination Optimization — MariaDB Docs](https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fpagination-optimization)\n\n*For topics not covered here, see the official MariaDB documentation at [mariadb.com\u002Fdocs](https:\u002F\u002Fmariadb.com\u002Fdocs).*\n",{"data":35,"body":36},{"name":4,"description":6},{"type":37,"children":38},"root",[39,47,57,111,118,415,421,448,456,476,514,539,557,580,612,644,650,662,676,684,875,910,924,949,989,995,1002,1014,1086,1091,1122,1128,1140,1179,1185,1265,1271,1296,1354,1367,1373,1385,1569,1574,1588,1638,1644,1662,1692,1714,1786,1813,1819,1837,1914,1919,1958,1971,1977,1982,2028,2042,2074,2084,2106,2142,2148,2153,2222,2230,2379,2384,2390,2395,2512,2518,2523,2670,2676,2681,2780,2786,2791,2893,2898,2904,2924,2947,2955,3307,3323,3386,3399,3405,3430,3476,3522,3528,3533,3658,3664,3746,3762],{"type":40,"tag":41,"props":42,"children":43},"element","h1",{"id":4},[44],{"type":45,"value":46},"text","MariaDB Query Optimization",{"type":40,"tag":48,"props":49,"children":50},"p",{},[51],{"type":40,"tag":52,"props":53,"children":54},"em",{},[55],{"type":45,"value":56},"Last updated: 2026-06-05",{"type":40,"tag":58,"props":59,"children":60},"blockquote",{},[61,88],{"type":40,"tag":48,"props":62,"children":63},{},[64,70,72,79,81,86],{"type":40,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":45,"value":69},"Requires:",{"type":45,"value":71}," MariaDB 10.1+ for ",{"type":40,"tag":73,"props":74,"children":76},"code",{"className":75},[],[77],{"type":45,"value":78},"ANALYZE",{"type":45,"value":80}," and histograms; optimizer improvements through ",{"type":40,"tag":65,"props":82,"children":83},{},[84],{"type":45,"value":85},"11.8 LTS",{"type":45,"value":87}," (GA May 2025) form the baseline below.",{"type":40,"tag":48,"props":89,"children":90},{},[91,96,98,102,104,109],{"type":40,"tag":65,"props":92,"children":93},{},[94],{"type":45,"value":95},"Default context:",{"type":45,"value":97}," Assume MariaDB ",{"type":40,"tag":65,"props":99,"children":100},{},[101],{"type":45,"value":85},{"type":45,"value":103}," unless the user states another version. Features marked ",{"type":40,"tag":65,"props":105,"children":106},{},[107],{"type":45,"value":108},"12.x",{"type":45,"value":110}," may be suggested when relevant (including as upgrade options), but always state the minimum version — do not present them as available on 11.8.",{"type":40,"tag":112,"props":113,"children":115},"h2",{"id":114},"what-llms-get-wrong",[116],{"type":45,"value":117},"What LLMs Get Wrong",{"type":40,"tag":119,"props":120,"children":121},"table",{},[122,141],{"type":40,"tag":123,"props":124,"children":125},"thead",{},[126],{"type":40,"tag":127,"props":128,"children":129},"tr",{},[130,136],{"type":40,"tag":131,"props":132,"children":133},"th",{},[134],{"type":45,"value":135},"Pattern",{"type":40,"tag":131,"props":137,"children":138},{},[139],{"type":45,"value":140},"What to do instead",{"type":40,"tag":142,"props":143,"children":144},"tbody",{},[145,171,209,222,243,277,296,330,375],{"type":40,"tag":127,"props":146,"children":147},{},[148,158],{"type":40,"tag":149,"props":150,"children":151},"td",{},[152],{"type":40,"tag":73,"props":153,"children":155},{"className":154},[],[156],{"type":45,"value":157},"SELECT * FROM table LIMIT 10 OFFSET 50000",{"type":40,"tag":149,"props":159,"children":160},{},[161,163,169],{"type":45,"value":162},"Use cursor-based pagination — ",{"type":40,"tag":73,"props":164,"children":166},{"className":165},[],[167],{"type":45,"value":168},"OFFSET",{"type":45,"value":170}," scans all skipped rows",{"type":40,"tag":127,"props":172,"children":173},{},[174,179],{"type":40,"tag":149,"props":175,"children":176},{},[177],{"type":45,"value":178},"Blanket rule \"functions on indexed columns kill indexes\"",{"type":40,"tag":149,"props":180,"children":181},{},[182,184,190,192,198,200,207],{"type":45,"value":183},"Outdated on MariaDB 11.1+\u002F11.3+ for many cases. ",{"type":40,"tag":73,"props":185,"children":187},{"className":186},[],[188],{"type":45,"value":189},"YEAR(col) = const",{"type":45,"value":191}," and ",{"type":40,"tag":73,"props":193,"children":195},{"className":194},[],[196],{"type":45,"value":197},"UPPER(col) = const",{"type":45,"value":199}," on case-insensitive columns can now use indexes — see ",{"type":40,"tag":201,"props":202,"children":204},"a",{"href":203},"#functions-on-indexed-columns",[205],{"type":45,"value":206},"Functions on indexed columns",{"type":45,"value":208}," below",{"type":40,"tag":127,"props":210,"children":211},{},[212,217],{"type":40,"tag":149,"props":213,"children":214},{},[215],{"type":45,"value":216},"Adding an index to a low-cardinality column (boolean, status with 2-3 values)",{"type":40,"tag":149,"props":218,"children":219},{},[220],{"type":45,"value":221},"Optimizer skips indexes with low selectivity and does a table scan anyway",{"type":40,"tag":127,"props":223,"children":224},{},[225,238],{"type":40,"tag":149,"props":226,"children":227},{},[228,230,236],{"type":45,"value":229},"Not running ",{"type":40,"tag":73,"props":231,"children":233},{"className":232},[],[234],{"type":45,"value":235},"ANALYZE TABLE",{"type":45,"value":237}," after bulk inserts",{"type":40,"tag":149,"props":239,"children":240},{},[241],{"type":45,"value":242},"Histogram statistics become stale; optimizer makes poor plan choices",{"type":40,"tag":127,"props":244,"children":245},{},[246,265],{"type":40,"tag":149,"props":247,"children":248},{},[249,251,257,259],{"type":45,"value":250},"Composite index ",{"type":40,"tag":73,"props":252,"children":254},{"className":253},[],[255],{"type":45,"value":256},"(a, b, c)",{"type":45,"value":258}," used in ",{"type":40,"tag":73,"props":260,"children":262},{"className":261},[],[263],{"type":45,"value":264},"WHERE b = 1 AND c = 2",{"type":40,"tag":149,"props":266,"children":267},{},[268,270,275],{"type":45,"value":269},"Leftmost prefix rule: this skips ",{"type":40,"tag":73,"props":271,"children":273},{"className":272},[],[274],{"type":45,"value":201},{"type":45,"value":276},", so the index is not used",{"type":40,"tag":127,"props":278,"children":279},{},[280,291],{"type":40,"tag":149,"props":281,"children":282},{},[283,289],{"type":40,"tag":73,"props":284,"children":286},{"className":285},[],[287],{"type":45,"value":288},"SELECT *",{"type":45,"value":290}," in queries with JOINs",{"type":40,"tag":149,"props":292,"children":293},{},[294],{"type":45,"value":295},"Name only the columns needed — prevents accidentally blocking covering indexes",{"type":40,"tag":127,"props":297,"children":298},{},[299,310],{"type":40,"tag":149,"props":300,"children":301},{},[302,308],{"type":40,"tag":73,"props":303,"children":305},{"className":304},[],[306],{"type":45,"value":307},"ALTER TABLE t ALTER INDEX idx INVISIBLE",{"type":45,"value":309}," to disable an index",{"type":40,"tag":149,"props":311,"children":312},{},[313,315,321,323,329],{"type":45,"value":314},"That's MySQL syntax. MariaDB uses ",{"type":40,"tag":73,"props":316,"children":318},{"className":317},[],[319],{"type":45,"value":320},"IGNORED",{"type":45,"value":322}," — see ",{"type":40,"tag":201,"props":324,"children":326},{"href":325},"#ignored-indexes-not-invisible",[327],{"type":45,"value":328},"Ignored Indexes",{"type":45,"value":208},{"type":40,"tag":127,"props":331,"children":332},{},[333,346],{"type":40,"tag":149,"props":334,"children":335},{},[336,338,344],{"type":45,"value":337},"Jump straight to ",{"type":40,"tag":73,"props":339,"children":341},{"className":340},[],[342],{"type":45,"value":343},"EXPLAIN",{"type":45,"value":345}," or indexes on a slow server",{"type":40,"tag":149,"props":347,"children":348},{},[349,351,359,361,366,368,373],{"type":45,"value":350},"Enable ",{"type":40,"tag":201,"props":352,"children":356},{"href":353,"rel":354},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsystem-tables\u002Fperformance-schema\u002Fperformance-schema-overview",[355],"nofollow",[357],{"type":45,"value":358},"Performance Schema",{"type":45,"value":360}," at ",{"type":40,"tag":65,"props":362,"children":363},{},[364],{"type":45,"value":365},"startup",{"type":45,"value":367}," first — it is ",{"type":40,"tag":65,"props":369,"children":370},{},[371],{"type":45,"value":372},"off by default",{"type":45,"value":374}," and cannot be turned on at runtime",{"type":40,"tag":127,"props":376,"children":377},{},[378,389],{"type":40,"tag":149,"props":379,"children":380},{},[381,387],{"type":40,"tag":73,"props":382,"children":384},{"className":383},[],[385],{"type":45,"value":386},"SET GLOBAL performance_schema = ON",{"type":45,"value":388}," to enable monitoring",{"type":40,"tag":149,"props":390,"children":391},{},[392,394,400,402,408,410],{"type":45,"value":393},"Performance Schema requires ",{"type":40,"tag":73,"props":395,"children":397},{"className":396},[],[398],{"type":45,"value":399},"performance_schema=ON",{"type":45,"value":401}," in ",{"type":40,"tag":73,"props":403,"children":405},{"className":404},[],[406],{"type":45,"value":407},"my.cnf",{"type":45,"value":409}," and a ",{"type":40,"tag":65,"props":411,"children":412},{},[413],{"type":45,"value":414},"server restart",{"type":40,"tag":112,"props":416,"children":418},{"id":417},"performance-schema-enable-first",[419],{"type":45,"value":420},"Performance Schema (enable first)",{"type":40,"tag":48,"props":422,"children":423},{},[424,426,431,433,438,440,446],{"type":45,"value":425},"Before ",{"type":40,"tag":73,"props":427,"children":429},{"className":428},[],[430],{"type":45,"value":343},{"type":45,"value":432},", indexes, or query rewrites, confirm the server can observe what queries are doing. MariaDB's ",{"type":40,"tag":201,"props":434,"children":436},{"href":353,"rel":435},[355],[437],{"type":45,"value":358},{"type":45,"value":439}," is the built-in monitoring layer (10.5+: ~80 tables in the ",{"type":40,"tag":73,"props":441,"children":443},{"className":442},[],[444],{"type":45,"value":445},"performance_schema",{"type":45,"value":447}," database).",{"type":40,"tag":48,"props":449,"children":450},{},[451],{"type":40,"tag":65,"props":452,"children":453},{},[454],{"type":45,"value":455},"Check status:",{"type":40,"tag":457,"props":458,"children":462},"pre",{"className":459,"code":460,"language":22,"meta":461,"style":461},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","SHOW VARIABLES LIKE 'performance_schema';\n","",[463],{"type":40,"tag":73,"props":464,"children":465},{"__ignoreMap":461},[466],{"type":40,"tag":467,"props":468,"children":471},"span",{"class":469,"line":470},"line",1,[472],{"type":40,"tag":467,"props":473,"children":474},{},[475],{"type":45,"value":460},{"type":40,"tag":48,"props":477,"children":478},{},[479,484,486,491,492,497,499,505,507,512],{"type":40,"tag":65,"props":480,"children":481},{},[482],{"type":45,"value":483},"Critical:",{"type":45,"value":485}," Performance Schema is ",{"type":40,"tag":65,"props":487,"children":488},{},[489],{"type":45,"value":490},"disabled by default",{"type":45,"value":191},{"type":40,"tag":65,"props":493,"children":494},{},[495],{"type":45,"value":496},"cannot be enabled at runtime",{"type":45,"value":498},". If ",{"type":40,"tag":73,"props":500,"children":502},{"className":501},[],[503],{"type":45,"value":504},"OFF",{"type":45,"value":506},", add to ",{"type":40,"tag":73,"props":508,"children":510},{"className":509},[],[511],{"type":45,"value":407},{"type":45,"value":513}," and restart:",{"type":40,"tag":457,"props":515,"children":519},{"className":516,"code":517,"language":518,"meta":461,"style":461},"language-ini shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[mysqld]\nperformance_schema=ON\n","ini",[520],{"type":40,"tag":73,"props":521,"children":522},{"__ignoreMap":461},[523,531],{"type":40,"tag":467,"props":524,"children":525},{"class":469,"line":470},[526],{"type":40,"tag":467,"props":527,"children":528},{},[529],{"type":45,"value":530},"[mysqld]\n",{"type":40,"tag":467,"props":532,"children":533},{"class":469,"line":27},[534],{"type":40,"tag":467,"props":535,"children":536},{},[537],{"type":45,"value":538},"performance_schema=ON\n",{"type":40,"tag":48,"props":540,"children":541},{},[542,547,549,555],{"type":40,"tag":65,"props":543,"children":544},{},[545],{"type":45,"value":546},"After restart",{"type":45,"value":548},", enable the consumers and instruments you need. Scope with ",{"type":40,"tag":73,"props":550,"children":552},{"className":551},[],[553],{"type":45,"value":554},"WHERE NAME LIKE '...'",{"type":45,"value":556}," rather than enabling everything blindly in production — see the overview doc:",{"type":40,"tag":457,"props":558,"children":560},{"className":459,"code":559,"language":22,"meta":461,"style":461},"UPDATE performance_schema.setup_consumers SET ENABLED = 'YES';\nUPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES';\n",[561],{"type":40,"tag":73,"props":562,"children":563},{"__ignoreMap":461},[564,572],{"type":40,"tag":467,"props":565,"children":566},{"class":469,"line":470},[567],{"type":40,"tag":467,"props":568,"children":569},{},[570],{"type":45,"value":571},"UPDATE performance_schema.setup_consumers SET ENABLED = 'YES';\n",{"type":40,"tag":467,"props":573,"children":574},{"class":469,"line":27},[575],{"type":40,"tag":467,"props":576,"children":577},{},[578],{"type":45,"value":579},"UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES';\n",{"type":40,"tag":48,"props":581,"children":582},{},[583,585,590,592,597,598,603,605,610],{"type":45,"value":584},"Use ",{"type":40,"tag":73,"props":586,"children":588},{"className":587},[],[589],{"type":45,"value":445},{"type":45,"value":591}," (waits, stages, statements, and related summary tables) to see where time goes; then use ",{"type":40,"tag":73,"props":593,"children":595},{"className":594},[],[596],{"type":45,"value":343},{"type":45,"value":191},{"type":40,"tag":73,"props":599,"children":601},{"className":600},[],[602],{"type":45,"value":78},{"type":45,"value":604}," below to understand why the optimizer chose a plan. On ",{"type":40,"tag":65,"props":606,"children":607},{},[608],{"type":45,"value":609},"10.7.1+",{"type":45,"value":611},", column comments help interpret tables:",{"type":40,"tag":457,"props":613,"children":615},{"className":459,"code":614,"language":22,"meta":461,"style":461},"SELECT column_name, column_comment\n  FROM information_schema.columns\n WHERE table_schema = 'performance_schema' AND table_name = 'events_statements_summary_by_digest';\n",[616],{"type":40,"tag":73,"props":617,"children":618},{"__ignoreMap":461},[619,627,635],{"type":40,"tag":467,"props":620,"children":621},{"class":469,"line":470},[622],{"type":40,"tag":467,"props":623,"children":624},{},[625],{"type":45,"value":626},"SELECT column_name, column_comment\n",{"type":40,"tag":467,"props":628,"children":629},{"class":469,"line":27},[630],{"type":40,"tag":467,"props":631,"children":632},{},[633],{"type":45,"value":634},"  FROM information_schema.columns\n",{"type":40,"tag":467,"props":636,"children":638},{"class":469,"line":637},3,[639],{"type":40,"tag":467,"props":640,"children":641},{},[642],{"type":45,"value":643}," WHERE table_schema = 'performance_schema' AND table_name = 'events_statements_summary_by_digest';\n",{"type":40,"tag":112,"props":645,"children":647},{"id":646},"reading-explain",[648],{"type":45,"value":649},"Reading EXPLAIN",{"type":40,"tag":48,"props":651,"children":652},{},[653,655,660],{"type":45,"value":654},"With Performance Schema available when diagnosing production slowness, run ",{"type":40,"tag":73,"props":656,"children":658},{"className":657},[],[659],{"type":45,"value":343},{"type":45,"value":661}," to inspect the optimizer's plan:",{"type":40,"tag":457,"props":663,"children":665},{"className":459,"code":664,"language":22,"meta":461,"style":461},"EXPLAIN SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC LIMIT 10;\n",[666],{"type":40,"tag":73,"props":667,"children":668},{"__ignoreMap":461},[669],{"type":40,"tag":467,"props":670,"children":671},{"class":469,"line":470},[672],{"type":40,"tag":467,"props":673,"children":674},{},[675],{"type":45,"value":664},{"type":40,"tag":48,"props":677,"children":678},{},[679],{"type":40,"tag":65,"props":680,"children":681},{},[682],{"type":45,"value":683},"Red flags in the output:",{"type":40,"tag":119,"props":685,"children":686},{},[687,708],{"type":40,"tag":123,"props":688,"children":689},{},[690],{"type":40,"tag":127,"props":691,"children":692},{},[693,698,703],{"type":40,"tag":131,"props":694,"children":695},{},[696],{"type":45,"value":697},"Field",{"type":40,"tag":131,"props":699,"children":700},{},[701],{"type":45,"value":702},"Red flag",{"type":40,"tag":131,"props":704,"children":705},{},[706],{"type":45,"value":707},"What it means",{"type":40,"tag":142,"props":709,"children":710},{},[711,737,763,785,811,850],{"type":40,"tag":127,"props":712,"children":713},{},[714,723,732],{"type":40,"tag":149,"props":715,"children":716},{},[717],{"type":40,"tag":73,"props":718,"children":720},{"className":719},[],[721],{"type":45,"value":722},"type",{"type":40,"tag":149,"props":724,"children":725},{},[726],{"type":40,"tag":73,"props":727,"children":729},{"className":728},[],[730],{"type":45,"value":731},"ALL",{"type":40,"tag":149,"props":733,"children":734},{},[735],{"type":45,"value":736},"Full table scan — missing index or index not used",{"type":40,"tag":127,"props":738,"children":739},{},[740,749,758],{"type":40,"tag":149,"props":741,"children":742},{},[743],{"type":40,"tag":73,"props":744,"children":746},{"className":745},[],[747],{"type":45,"value":748},"key",{"type":40,"tag":149,"props":750,"children":751},{},[752],{"type":40,"tag":73,"props":753,"children":755},{"className":754},[],[756],{"type":45,"value":757},"NULL",{"type":40,"tag":149,"props":759,"children":760},{},[761],{"type":45,"value":762},"No index used despite one existing — check for function on column or type mismatch",{"type":40,"tag":127,"props":764,"children":765},{},[766,775,780],{"type":40,"tag":149,"props":767,"children":768},{},[769],{"type":40,"tag":73,"props":770,"children":772},{"className":771},[],[773],{"type":45,"value":774},"rows",{"type":40,"tag":149,"props":776,"children":777},{},[778],{"type":45,"value":779},"Very high number",{"type":40,"tag":149,"props":781,"children":782},{},[783],{"type":45,"value":784},"Optimizer estimates scanning many rows",{"type":40,"tag":127,"props":786,"children":787},{},[788,797,806],{"type":40,"tag":149,"props":789,"children":790},{},[791],{"type":40,"tag":73,"props":792,"children":794},{"className":793},[],[795],{"type":45,"value":796},"Extra",{"type":40,"tag":149,"props":798,"children":799},{},[800],{"type":40,"tag":73,"props":801,"children":803},{"className":802},[],[804],{"type":45,"value":805},"Using filesort",{"type":40,"tag":149,"props":807,"children":808},{},[809],{"type":45,"value":810},"Expensive sort not covered by an index",{"type":40,"tag":127,"props":812,"children":813},{},[814,822,831],{"type":40,"tag":149,"props":815,"children":816},{},[817],{"type":40,"tag":73,"props":818,"children":820},{"className":819},[],[821],{"type":45,"value":796},{"type":40,"tag":149,"props":823,"children":824},{},[825],{"type":40,"tag":73,"props":826,"children":828},{"className":827},[],[829],{"type":45,"value":830},"Using temporary",{"type":40,"tag":149,"props":832,"children":833},{},[834,836,842,844],{"type":45,"value":835},"Temp table created — often from ",{"type":40,"tag":73,"props":837,"children":839},{"className":838},[],[840],{"type":45,"value":841},"GROUP BY",{"type":45,"value":843}," or ",{"type":40,"tag":73,"props":845,"children":847},{"className":846},[],[848],{"type":45,"value":849},"DISTINCT",{"type":40,"tag":127,"props":851,"children":852},{},[853,861,870],{"type":40,"tag":149,"props":854,"children":855},{},[856],{"type":40,"tag":73,"props":857,"children":859},{"className":858},[],[860],{"type":45,"value":796},{"type":40,"tag":149,"props":862,"children":863},{},[864],{"type":40,"tag":73,"props":865,"children":867},{"className":866},[],[868],{"type":45,"value":869},"Using index",{"type":40,"tag":149,"props":871,"children":872},{},[873],{"type":45,"value":874},"✅ Good — covering index, no table row access needed",{"type":40,"tag":48,"props":876,"children":877},{},[878,886,888,893,895,900,902,908],{"type":40,"tag":65,"props":879,"children":880},{},[881],{"type":40,"tag":73,"props":882,"children":884},{"className":883},[],[885],{"type":45,"value":78},{"type":45,"value":887}," statement (MariaDB 10.1+) actually executes the query and shows real row counts vs. estimates — more reliable than ",{"type":40,"tag":73,"props":889,"children":891},{"className":890},[],[892],{"type":45,"value":343},{"type":45,"value":894}," alone. Note: MariaDB uses ",{"type":40,"tag":73,"props":896,"children":898},{"className":897},[],[899],{"type":45,"value":78},{"type":45,"value":901},", not ",{"type":40,"tag":73,"props":903,"children":905},{"className":904},[],[906],{"type":45,"value":907},"EXPLAIN ANALYZE",{"type":45,"value":909},":",{"type":40,"tag":457,"props":911,"children":913},{"className":459,"code":912,"language":22,"meta":461,"style":461},"ANALYZE SELECT * FROM orders WHERE customer_id = 42;\n",[914],{"type":40,"tag":73,"props":915,"children":916},{"__ignoreMap":461},[917],{"type":40,"tag":467,"props":918,"children":919},{"class":469,"line":470},[920],{"type":40,"tag":467,"props":921,"children":922},{},[923],{"type":45,"value":912},{"type":40,"tag":48,"props":925,"children":926},{},[927,932,934,940,942,947],{"type":40,"tag":65,"props":928,"children":929},{},[930],{"type":45,"value":931},"Optimizer Trace",{"type":45,"value":933}," shows the optimizer's full decision process. Since MariaDB 12.1 the trace can include full table and view definitions (",{"type":40,"tag":73,"props":935,"children":937},{"className":936},[],[938],{"type":45,"value":939},"optimizer_record_context",{"type":45,"value":941}," system variable). Since 13.0 it also includes the specific statistics (histograms, index stats) used for cardinality estimates — together they're powerful for diagnosing surprising ",{"type":40,"tag":73,"props":943,"children":945},{"className":944},[],[946],{"type":45,"value":774},{"type":45,"value":948}," estimates:",{"type":40,"tag":457,"props":950,"children":952},{"className":459,"code":951,"language":22,"meta":461,"style":461},"SET optimizer_trace = 'enabled=on';\nSELECT * FROM orders WHERE customer_id = 42;\nSELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\\G\nSET optimizer_trace = 'enabled=off';\n",[953],{"type":40,"tag":73,"props":954,"children":955},{"__ignoreMap":461},[956,964,972,980],{"type":40,"tag":467,"props":957,"children":958},{"class":469,"line":470},[959],{"type":40,"tag":467,"props":960,"children":961},{},[962],{"type":45,"value":963},"SET optimizer_trace = 'enabled=on';\n",{"type":40,"tag":467,"props":965,"children":966},{"class":469,"line":27},[967],{"type":40,"tag":467,"props":968,"children":969},{},[970],{"type":45,"value":971},"SELECT * FROM orders WHERE customer_id = 42;\n",{"type":40,"tag":467,"props":973,"children":974},{"class":469,"line":637},[975],{"type":40,"tag":467,"props":976,"children":977},{},[978],{"type":45,"value":979},"SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\\G\n",{"type":40,"tag":467,"props":981,"children":983},{"class":469,"line":982},4,[984],{"type":40,"tag":467,"props":985,"children":986},{},[987],{"type":45,"value":988},"SET optimizer_trace = 'enabled=off';\n",{"type":40,"tag":112,"props":990,"children":992},{"id":991},"indexing-rules",[993],{"type":45,"value":994},"Indexing Rules",{"type":40,"tag":996,"props":997,"children":999},"h3",{"id":998},"the-leftmost-prefix-rule",[1000],{"type":45,"value":1001},"The Leftmost Prefix Rule",{"type":40,"tag":48,"props":1003,"children":1004},{},[1005,1007,1012],{"type":45,"value":1006},"For a composite index ",{"type":40,"tag":73,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":45,"value":256},{"type":45,"value":1013},", MariaDB can use:",{"type":40,"tag":1015,"props":1016,"children":1017},"ul",{},[1018,1030,1040,1050,1068],{"type":40,"tag":1019,"props":1020,"children":1021},"li",{},[1022,1028],{"type":40,"tag":73,"props":1023,"children":1025},{"className":1024},[],[1026],{"type":45,"value":1027},"WHERE a = 1",{"type":45,"value":1029}," ✅",{"type":40,"tag":1019,"props":1031,"children":1032},{},[1033,1039],{"type":40,"tag":73,"props":1034,"children":1036},{"className":1035},[],[1037],{"type":45,"value":1038},"WHERE a = 1 AND b = 2",{"type":45,"value":1029},{"type":40,"tag":1019,"props":1041,"children":1042},{},[1043,1049],{"type":40,"tag":73,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":45,"value":1048},"WHERE a = 1 AND b = 2 AND c = 3",{"type":45,"value":1029},{"type":40,"tag":1019,"props":1051,"children":1052},{},[1053,1059,1061,1066],{"type":40,"tag":73,"props":1054,"children":1056},{"className":1055},[],[1057],{"type":45,"value":1058},"WHERE b = 2",{"type":45,"value":1060}," ✗ — skips ",{"type":40,"tag":73,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":45,"value":201},{"type":45,"value":1067},", index not used",{"type":40,"tag":1019,"props":1069,"children":1070},{},[1071,1077,1079,1084],{"type":40,"tag":73,"props":1072,"children":1074},{"className":1073},[],[1075],{"type":45,"value":1076},"WHERE a = 1 AND c = 3",{"type":45,"value":1078}," — only ",{"type":40,"tag":73,"props":1080,"children":1082},{"className":1081},[],[1083],{"type":45,"value":201},{"type":45,"value":1085}," part is used",{"type":40,"tag":48,"props":1087,"children":1088},{},[1089],{"type":45,"value":1090},"Put the most selective equality conditions first, then range conditions last:",{"type":40,"tag":457,"props":1092,"children":1094},{"className":459,"code":1093,"language":22,"meta":461,"style":461},"-- Query: WHERE status = 'active' AND created_at > '2025-01-01' ORDER BY created_at\nINDEX (status, created_at)  -- ✅ equality first, range last\nINDEX (created_at, status)  -- ✗ range first breaks the prefix for status\n",[1095],{"type":40,"tag":73,"props":1096,"children":1097},{"__ignoreMap":461},[1098,1106,1114],{"type":40,"tag":467,"props":1099,"children":1100},{"class":469,"line":470},[1101],{"type":40,"tag":467,"props":1102,"children":1103},{},[1104],{"type":45,"value":1105},"-- Query: WHERE status = 'active' AND created_at > '2025-01-01' ORDER BY created_at\n",{"type":40,"tag":467,"props":1107,"children":1108},{"class":469,"line":27},[1109],{"type":40,"tag":467,"props":1110,"children":1111},{},[1112],{"type":45,"value":1113},"INDEX (status, created_at)  -- ✅ equality first, range last\n",{"type":40,"tag":467,"props":1115,"children":1116},{"class":469,"line":637},[1117],{"type":40,"tag":467,"props":1118,"children":1119},{},[1120],{"type":45,"value":1121},"INDEX (created_at, status)  -- ✗ range first breaks the prefix for status\n",{"type":40,"tag":996,"props":1123,"children":1125},{"id":1124},"covering-indexes",[1126],{"type":45,"value":1127},"Covering Indexes",{"type":40,"tag":48,"props":1129,"children":1130},{},[1131,1133,1138],{"type":45,"value":1132},"A covering index includes all columns needed by the query — no table row access needed (",{"type":40,"tag":73,"props":1134,"children":1136},{"className":1135},[],[1137],{"type":45,"value":869},{"type":45,"value":1139}," in EXPLAIN):",{"type":40,"tag":457,"props":1141,"children":1143},{"className":459,"code":1142,"language":22,"meta":461,"style":461},"-- Query fetches id, status, created_at for a customer\n-- Covering index includes all three:\nCREATE INDEX idx_customer_cover ON orders (customer_id, status, created_at);\n-- Now EXPLAIN shows: Extra = Using index\n",[1144],{"type":40,"tag":73,"props":1145,"children":1146},{"__ignoreMap":461},[1147,1155,1163,1171],{"type":40,"tag":467,"props":1148,"children":1149},{"class":469,"line":470},[1150],{"type":40,"tag":467,"props":1151,"children":1152},{},[1153],{"type":45,"value":1154},"-- Query fetches id, status, created_at for a customer\n",{"type":40,"tag":467,"props":1156,"children":1157},{"class":469,"line":27},[1158],{"type":40,"tag":467,"props":1159,"children":1160},{},[1161],{"type":45,"value":1162},"-- Covering index includes all three:\n",{"type":40,"tag":467,"props":1164,"children":1165},{"class":469,"line":637},[1166],{"type":40,"tag":467,"props":1167,"children":1168},{},[1169],{"type":45,"value":1170},"CREATE INDEX idx_customer_cover ON orders (customer_id, status, created_at);\n",{"type":40,"tag":467,"props":1172,"children":1173},{"class":469,"line":982},[1174],{"type":40,"tag":467,"props":1175,"children":1176},{},[1177],{"type":45,"value":1178},"-- Now EXPLAIN shows: Extra = Using index\n",{"type":40,"tag":996,"props":1180,"children":1182},{"id":1181},"when-not-to-add-an-index",[1183],{"type":45,"value":1184},"When NOT to Add an Index",{"type":40,"tag":1015,"props":1186,"children":1187},{},[1188,1222,1232],{"type":40,"tag":1019,"props":1189,"children":1190},{},[1191,1196,1198,1204,1206,1212,1214,1220],{"type":40,"tag":65,"props":1192,"children":1193},{},[1194],{"type":45,"value":1195},"Low-cardinality columns",{"type":45,"value":1197},": a ",{"type":40,"tag":73,"props":1199,"children":1201},{"className":1200},[],[1202],{"type":45,"value":1203},"status",{"type":45,"value":1205}," column with values ",{"type":40,"tag":73,"props":1207,"children":1209},{"className":1208},[],[1210],{"type":45,"value":1211},"active",{"type":45,"value":1213},"\u002F",{"type":40,"tag":73,"props":1215,"children":1217},{"className":1216},[],[1218],{"type":45,"value":1219},"inactive",{"type":45,"value":1221}," affects 50% of rows — the optimizer prefers a table scan. Index useful only when combined with other high-selectivity columns.",{"type":40,"tag":1019,"props":1223,"children":1224},{},[1225,1230],{"type":40,"tag":65,"props":1226,"children":1227},{},[1228],{"type":45,"value":1229},"Small tables",{"type":45,"value":1231}," (\u003C a few thousand rows): full scans are faster than index lookups for tiny tables.",{"type":40,"tag":1019,"props":1233,"children":1234},{},[1235,1240,1242,1248,1250,1256,1257,1263],{"type":40,"tag":65,"props":1236,"children":1237},{},[1238],{"type":45,"value":1239},"Write-heavy columns",{"type":45,"value":1241},": every index slows ",{"type":40,"tag":73,"props":1243,"children":1245},{"className":1244},[],[1246],{"type":45,"value":1247},"INSERT",{"type":45,"value":1249},", ",{"type":40,"tag":73,"props":1251,"children":1253},{"className":1252},[],[1254],{"type":45,"value":1255},"UPDATE",{"type":45,"value":1249},{"type":40,"tag":73,"props":1258,"children":1260},{"className":1259},[],[1261],{"type":45,"value":1262},"DELETE",{"type":45,"value":1264}," — don't index columns that are rarely queried.",{"type":40,"tag":996,"props":1266,"children":1268},{"id":1267},"ignored-indexes-not-invisible",[1269],{"type":45,"value":1270},"Ignored Indexes (not INVISIBLE)",{"type":40,"tag":48,"props":1272,"children":1273},{},[1274,1276,1281,1282,1287,1289,1295],{"type":45,"value":1275},"To make the optimizer skip an index without dropping it — useful for testing whether an index is actually needed before removing it — MariaDB uses ",{"type":40,"tag":73,"props":1277,"children":1279},{"className":1278},[],[1280],{"type":45,"value":320},{"type":45,"value":1249},{"type":40,"tag":65,"props":1283,"children":1284},{},[1285],{"type":45,"value":1286},"not",{"type":45,"value":1288}," MySQL's ",{"type":40,"tag":73,"props":1290,"children":1292},{"className":1291},[],[1293],{"type":45,"value":1294},"INVISIBLE",{"type":45,"value":909},{"type":40,"tag":457,"props":1297,"children":1299},{"className":459,"code":1298,"language":22,"meta":461,"style":461},"-- ✅ MariaDB syntax (10.6+):\nALTER TABLE demo ALTER INDEX index_name IGNORED;\nALTER TABLE demo ALTER INDEX index_name NOT IGNORED;  -- re-enable\n\n-- ✗ MySQL syntax — fails on MariaDB:\nALTER TABLE demo ALTER INDEX index_name INVISIBLE;\n",[1300],{"type":40,"tag":73,"props":1301,"children":1302},{"__ignoreMap":461},[1303,1311,1319,1327,1336,1345],{"type":40,"tag":467,"props":1304,"children":1305},{"class":469,"line":470},[1306],{"type":40,"tag":467,"props":1307,"children":1308},{},[1309],{"type":45,"value":1310},"-- ✅ MariaDB syntax (10.6+):\n",{"type":40,"tag":467,"props":1312,"children":1313},{"class":469,"line":27},[1314],{"type":40,"tag":467,"props":1315,"children":1316},{},[1317],{"type":45,"value":1318},"ALTER TABLE demo ALTER INDEX index_name IGNORED;\n",{"type":40,"tag":467,"props":1320,"children":1321},{"class":469,"line":637},[1322],{"type":40,"tag":467,"props":1323,"children":1324},{},[1325],{"type":45,"value":1326},"ALTER TABLE demo ALTER INDEX index_name NOT IGNORED;  -- re-enable\n",{"type":40,"tag":467,"props":1328,"children":1329},{"class":469,"line":982},[1330],{"type":40,"tag":467,"props":1331,"children":1333},{"emptyLinePlaceholder":1332},true,[1334],{"type":45,"value":1335},"\n",{"type":40,"tag":467,"props":1337,"children":1339},{"class":469,"line":1338},5,[1340],{"type":40,"tag":467,"props":1341,"children":1342},{},[1343],{"type":45,"value":1344},"-- ✗ MySQL syntax — fails on MariaDB:\n",{"type":40,"tag":467,"props":1346,"children":1348},{"class":469,"line":1347},6,[1349],{"type":40,"tag":467,"props":1350,"children":1351},{},[1352],{"type":45,"value":1353},"ALTER TABLE demo ALTER INDEX index_name INVISIBLE;\n",{"type":40,"tag":48,"props":1355,"children":1356},{},[1357,1359,1365],{"type":45,"value":1358},"The index is still maintained on writes; it's just hidden from the optimizer. A primary key cannot be ignored. See ",{"type":40,"tag":201,"props":1360,"children":1363},{"href":1361,"rel":1362},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Foptimization-and-indexes\u002Fignored-indexes",[355],[1364],{"type":45,"value":328},{"type":45,"value":1366},".",{"type":40,"tag":996,"props":1368,"children":1370},{"id":1369},"functions-on-indexed-columns",[1371],{"type":45,"value":1372},"Functions on Indexed Columns",{"type":40,"tag":48,"props":1374,"children":1375},{},[1376,1378,1383],{"type":45,"value":1377},"The classic rule \"any function on an indexed column disables the index\" is ",{"type":40,"tag":65,"props":1379,"children":1380},{},[1381],{"type":45,"value":1382},"outdated for MariaDB 11.1+ and 11.4 LTS",{"type":45,"value":1384},". The optimizer can now use indexes for a number of common function patterns:",{"type":40,"tag":119,"props":1386,"children":1387},{},[1388,1408],{"type":40,"tag":123,"props":1389,"children":1390},{},[1391],{"type":40,"tag":127,"props":1392,"children":1393},{},[1394,1398,1403],{"type":40,"tag":131,"props":1395,"children":1396},{},[1397],{"type":45,"value":135},{"type":40,"tag":131,"props":1399,"children":1400},{},[1401],{"type":45,"value":1402},"Works on the index?",{"type":40,"tag":131,"props":1404,"children":1405},{},[1406],{"type":45,"value":1407},"Since",{"type":40,"tag":142,"props":1409,"children":1410},{},[1411,1433,1454,1494,1524,1546],{"type":40,"tag":127,"props":1412,"children":1413},{},[1414,1423,1428],{"type":40,"tag":149,"props":1415,"children":1416},{},[1417],{"type":40,"tag":73,"props":1418,"children":1420},{"className":1419},[],[1421],{"type":45,"value":1422},"WHERE YEAR(col) = 2025",{"type":40,"tag":149,"props":1424,"children":1425},{},[1426],{"type":45,"value":1427},"✅ — sargable, picks the right range",{"type":40,"tag":149,"props":1429,"children":1430},{},[1431],{"type":45,"value":1432},"11.1+ (MDEV-8320)",{"type":40,"tag":127,"props":1434,"children":1435},{},[1436,1445,1450],{"type":40,"tag":149,"props":1437,"children":1438},{},[1439],{"type":40,"tag":73,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":45,"value":1444},"WHERE DATE(col) \u003C= '2025-12-31'",{"type":40,"tag":149,"props":1446,"children":1447},{},[1448],{"type":45,"value":1449},"✅ — sargable",{"type":40,"tag":149,"props":1451,"children":1452},{},[1453],{"type":45,"value":1432},{"type":40,"tag":127,"props":1455,"children":1456},{},[1457,1476,1489],{"type":40,"tag":149,"props":1458,"children":1459},{},[1460,1466,1468,1474],{"type":40,"tag":73,"props":1461,"children":1463},{"className":1462},[],[1464],{"type":45,"value":1465},"WHERE UPPER(varchar_col) = '...'",{"type":45,"value":1467}," on a case-insensitive collation (e.g. ",{"type":40,"tag":73,"props":1469,"children":1471},{"className":1470},[],[1472],{"type":45,"value":1473},"utf8mb4_uca1400_ai_ci",{"type":45,"value":1475},")",{"type":40,"tag":149,"props":1477,"children":1478},{},[1479,1481,1487],{"type":45,"value":1480},"✅ — ",{"type":40,"tag":73,"props":1482,"children":1484},{"className":1483},[],[1485],{"type":45,"value":1486},"sargable_casefold=ON",{"type":45,"value":1488}," is the default",{"type":40,"tag":149,"props":1490,"children":1491},{},[1492],{"type":45,"value":1493},"11.3+ (MDEV-31496)",{"type":40,"tag":127,"props":1495,"children":1496},{},[1497,1506,1519],{"type":40,"tag":149,"props":1498,"children":1499},{},[1500],{"type":40,"tag":73,"props":1501,"children":1503},{"className":1502},[],[1504],{"type":45,"value":1505},"WHERE SUBSTR(col, 1, n) = 'abc'",{"type":40,"tag":149,"props":1507,"children":1508},{},[1509,1511,1517],{"type":45,"value":1510},"✅ — leading-prefix ",{"type":40,"tag":73,"props":1512,"children":1514},{"className":1513},[],[1515],{"type":45,"value":1516},"SUBSTR",{"type":45,"value":1518}," is optimized",{"type":40,"tag":149,"props":1520,"children":1521},{},[1522],{"type":45,"value":1523},"11.8+ (MDEV-34911)",{"type":40,"tag":127,"props":1525,"children":1526},{},[1527,1536,1541],{"type":40,"tag":149,"props":1528,"children":1529},{},[1530],{"type":40,"tag":73,"props":1531,"children":1533},{"className":1532},[],[1534],{"type":45,"value":1535},"WHERE LOWER(case_sensitive_col) = '...'",{"type":40,"tag":149,"props":1537,"children":1538},{},[1539],{"type":45,"value":1540},"✗ — index not used (collation isn't case-insensitive)",{"type":40,"tag":149,"props":1542,"children":1543},{},[1544],{"type":45,"value":1545},"—",{"type":40,"tag":127,"props":1547,"children":1548},{},[1549,1560,1565],{"type":40,"tag":149,"props":1550,"children":1551},{},[1552,1558],{"type":40,"tag":73,"props":1553,"children":1555},{"className":1554},[],[1556],{"type":45,"value":1557},"WHERE CAST(col AS UNSIGNED) = 1",{"type":45,"value":1559}," or other type-changing transforms",{"type":40,"tag":149,"props":1561,"children":1562},{},[1563],{"type":45,"value":1564},"✗ — index not used",{"type":40,"tag":149,"props":1566,"children":1567},{},[1568],{"type":45,"value":1545},{"type":40,"tag":48,"props":1570,"children":1571},{},[1572],{"type":45,"value":1573},"For cases that the optimizer still can't sargabilize, the rewrite-to-range pattern remains valid:",{"type":40,"tag":457,"props":1575,"children":1577},{"className":459,"code":1576,"language":22,"meta":461,"style":461},"WHERE created_at >= '2025-01-01' AND created_at \u003C '2026-01-01'\n",[1578],{"type":40,"tag":73,"props":1579,"children":1580},{"__ignoreMap":461},[1581],{"type":40,"tag":467,"props":1582,"children":1583},{"class":469,"line":470},[1584],{"type":40,"tag":467,"props":1585,"children":1586},{},[1587],{"type":45,"value":1576},{"type":40,"tag":48,"props":1589,"children":1590},{},[1591,1593,1598,1600,1605,1607,1613,1615,1621,1623,1629,1631,1637],{"type":45,"value":1592},"Verify with ",{"type":40,"tag":73,"props":1594,"children":1596},{"className":1595},[],[1597],{"type":45,"value":343},{"type":45,"value":1599}," rather than assuming: on 11.4+ many \"won't use the index\" rewrites are now no-ops. If ",{"type":40,"tag":73,"props":1601,"children":1603},{"className":1602},[],[1604],{"type":45,"value":343},{"type":45,"value":1606}," still shows ",{"type":40,"tag":73,"props":1608,"children":1610},{"className":1609},[],[1611],{"type":45,"value":1612},"type=ALL",{"type":45,"value":1614}," for a sargable pattern, check ",{"type":40,"tag":73,"props":1616,"children":1618},{"className":1617},[],[1619],{"type":45,"value":1620},"@@optimizer_switch",{"type":45,"value":1622}," for ",{"type":40,"tag":73,"props":1624,"children":1626},{"className":1625},[],[1627],{"type":45,"value":1628},"sargable_casefold",{"type":45,"value":1630}," and confirm the column's collation is ",{"type":40,"tag":73,"props":1632,"children":1634},{"className":1633},[],[1635],{"type":45,"value":1636},"_ci",{"type":45,"value":1366},{"type":40,"tag":996,"props":1639,"children":1641},{"id":1640},"functional-indexes-use-a-generated-column",[1642],{"type":45,"value":1643},"Functional Indexes: Use a Generated Column",{"type":40,"tag":48,"props":1645,"children":1646},{},[1647,1649,1654,1656,1660],{"type":45,"value":1648},"MySQL 8.0.13+ supports ",{"type":40,"tag":65,"props":1650,"children":1651},{},[1652],{"type":45,"value":1653},"functional key parts",{"type":45,"value":1655}," — indexing an expression directly with a doubled-parenthesis syntax. MariaDB does ",{"type":40,"tag":65,"props":1657,"children":1658},{},[1659],{"type":45,"value":1286},{"type":45,"value":1661}," support this:",{"type":40,"tag":457,"props":1663,"children":1665},{"className":459,"code":1664,"language":22,"meta":461,"style":461},"-- ✗ MySQL syntax — fails on MariaDB:\nCREATE INDEX idx_upper ON users ((UPPER(name)));\nALTER TABLE orders ADD INDEX ((total * quantity));\n",[1666],{"type":40,"tag":73,"props":1667,"children":1668},{"__ignoreMap":461},[1669,1676,1684],{"type":40,"tag":467,"props":1670,"children":1671},{"class":469,"line":470},[1672],{"type":40,"tag":467,"props":1673,"children":1674},{},[1675],{"type":45,"value":1344},{"type":40,"tag":467,"props":1677,"children":1678},{"class":469,"line":27},[1679],{"type":40,"tag":467,"props":1680,"children":1681},{},[1682],{"type":45,"value":1683},"CREATE INDEX idx_upper ON users ((UPPER(name)));\n",{"type":40,"tag":467,"props":1685,"children":1686},{"class":469,"line":637},[1687],{"type":40,"tag":467,"props":1688,"children":1689},{},[1690],{"type":45,"value":1691},"ALTER TABLE orders ADD INDEX ((total * quantity));\n",{"type":40,"tag":48,"props":1693,"children":1694},{},[1695,1697,1704,1706,1712],{"type":45,"value":1696},"In MariaDB, index a ",{"type":40,"tag":201,"props":1698,"children":1701},{"href":1699,"rel":1700},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsql-statements\u002Fdata-definition\u002Fcreate\u002Fgenerated-columns",[355],[1702],{"type":45,"value":1703},"generated (computed) column",{"type":45,"value":1705}," instead. A ",{"type":40,"tag":73,"props":1707,"children":1709},{"className":1708},[],[1710],{"type":45,"value":1711},"VIRTUAL",{"type":45,"value":1713}," column stores nothing and is computed on read; the index on it persists the expression's value, which is what gets searched:",{"type":40,"tag":457,"props":1715,"children":1717},{"className":459,"code":1716,"language":22,"meta":461,"style":461},"-- ✅ MariaDB equivalent:\nALTER TABLE users\n  ADD COLUMN name_upper VARCHAR(255) AS (UPPER(name)) VIRTUAL,\n  ADD INDEX idx_name_upper (name_upper);\n\n-- Query the column the optimizer can resolve directly,\n-- or rely on virtual-column optimizer support (11.8+) for WHERE UPPER(name) = ...\nSELECT * FROM users WHERE name_upper = 'ALICE';\n",[1718],{"type":40,"tag":73,"props":1719,"children":1720},{"__ignoreMap":461},[1721,1729,1737,1745,1753,1760,1768,1777],{"type":40,"tag":467,"props":1722,"children":1723},{"class":469,"line":470},[1724],{"type":40,"tag":467,"props":1725,"children":1726},{},[1727],{"type":45,"value":1728},"-- ✅ MariaDB equivalent:\n",{"type":40,"tag":467,"props":1730,"children":1731},{"class":469,"line":27},[1732],{"type":40,"tag":467,"props":1733,"children":1734},{},[1735],{"type":45,"value":1736},"ALTER TABLE users\n",{"type":40,"tag":467,"props":1738,"children":1739},{"class":469,"line":637},[1740],{"type":40,"tag":467,"props":1741,"children":1742},{},[1743],{"type":45,"value":1744},"  ADD COLUMN name_upper VARCHAR(255) AS (UPPER(name)) VIRTUAL,\n",{"type":40,"tag":467,"props":1746,"children":1747},{"class":469,"line":982},[1748],{"type":40,"tag":467,"props":1749,"children":1750},{},[1751],{"type":45,"value":1752},"  ADD INDEX idx_name_upper (name_upper);\n",{"type":40,"tag":467,"props":1754,"children":1755},{"class":469,"line":1338},[1756],{"type":40,"tag":467,"props":1757,"children":1758},{"emptyLinePlaceholder":1332},[1759],{"type":45,"value":1335},{"type":40,"tag":467,"props":1761,"children":1762},{"class":469,"line":1347},[1763],{"type":40,"tag":467,"props":1764,"children":1765},{},[1766],{"type":45,"value":1767},"-- Query the column the optimizer can resolve directly,\n",{"type":40,"tag":467,"props":1769,"children":1771},{"class":469,"line":1770},7,[1772],{"type":40,"tag":467,"props":1773,"children":1774},{},[1775],{"type":45,"value":1776},"-- or rely on virtual-column optimizer support (11.8+) for WHERE UPPER(name) = ...\n",{"type":40,"tag":467,"props":1778,"children":1780},{"class":469,"line":1779},8,[1781],{"type":40,"tag":467,"props":1782,"children":1783},{},[1784],{"type":45,"value":1785},"SELECT * FROM users WHERE name_upper = 'ALICE';\n",{"type":40,"tag":48,"props":1787,"children":1788},{},[1789,1791,1797,1798,1804,1806,1811],{"type":45,"value":1790},"Note that for many simple cases (",{"type":40,"tag":73,"props":1792,"children":1794},{"className":1793},[],[1795],{"type":45,"value":1796},"YEAR(col)",{"type":45,"value":1249},{"type":40,"tag":73,"props":1799,"children":1801},{"className":1800},[],[1802],{"type":45,"value":1803},"UPPER(col)",{"type":45,"value":1805}," on ",{"type":40,"tag":73,"props":1807,"children":1809},{"className":1808},[],[1810],{"type":45,"value":1636},{"type":45,"value":1812}," collations) MariaDB 11.1+ no longer needs an indexed expression at all — see the table above. Reach for a generated column when the expression isn't sargable on its own.",{"type":40,"tag":112,"props":1814,"children":1816},{"id":1815},"pagination-cursor-based-instead-of-offset",[1817],{"type":45,"value":1818},"Pagination: Cursor-Based Instead of OFFSET",{"type":40,"tag":48,"props":1820,"children":1821},{},[1822,1827,1829,1835],{"type":40,"tag":73,"props":1823,"children":1825},{"className":1824},[],[1826],{"type":45,"value":168},{"type":45,"value":1828}," is a hidden performance trap. ",{"type":40,"tag":73,"props":1830,"children":1832},{"className":1831},[],[1833],{"type":45,"value":1834},"LIMIT 10 OFFSET 50000",{"type":45,"value":1836}," scans and discards 50,000 rows on every page load.",{"type":40,"tag":457,"props":1838,"children":1840},{"className":459,"code":1839,"language":22,"meta":461,"style":461},"-- ✗ Slow — scans 50,000 rows to skip them:\nSELECT id, title FROM posts ORDER BY id DESC LIMIT 10 OFFSET 50000;\n\n-- ✅ Fast — index seek directly to the cursor position:\n-- First page:\nSELECT id, title FROM posts ORDER BY id DESC LIMIT 10;\n\n-- Next page (pass last id from previous result as $last_id):\nSELECT id, title FROM posts WHERE id \u003C $last_id ORDER BY id DESC LIMIT 10;\n",[1841],{"type":40,"tag":73,"props":1842,"children":1843},{"__ignoreMap":461},[1844,1852,1860,1867,1875,1883,1891,1898,1906],{"type":40,"tag":467,"props":1845,"children":1846},{"class":469,"line":470},[1847],{"type":40,"tag":467,"props":1848,"children":1849},{},[1850],{"type":45,"value":1851},"-- ✗ Slow — scans 50,000 rows to skip them:\n",{"type":40,"tag":467,"props":1853,"children":1854},{"class":469,"line":27},[1855],{"type":40,"tag":467,"props":1856,"children":1857},{},[1858],{"type":45,"value":1859},"SELECT id, title FROM posts ORDER BY id DESC LIMIT 10 OFFSET 50000;\n",{"type":40,"tag":467,"props":1861,"children":1862},{"class":469,"line":637},[1863],{"type":40,"tag":467,"props":1864,"children":1865},{"emptyLinePlaceholder":1332},[1866],{"type":45,"value":1335},{"type":40,"tag":467,"props":1868,"children":1869},{"class":469,"line":982},[1870],{"type":40,"tag":467,"props":1871,"children":1872},{},[1873],{"type":45,"value":1874},"-- ✅ Fast — index seek directly to the cursor position:\n",{"type":40,"tag":467,"props":1876,"children":1877},{"class":469,"line":1338},[1878],{"type":40,"tag":467,"props":1879,"children":1880},{},[1881],{"type":45,"value":1882},"-- First page:\n",{"type":40,"tag":467,"props":1884,"children":1885},{"class":469,"line":1347},[1886],{"type":40,"tag":467,"props":1887,"children":1888},{},[1889],{"type":45,"value":1890},"SELECT id, title FROM posts ORDER BY id DESC LIMIT 10;\n",{"type":40,"tag":467,"props":1892,"children":1893},{"class":469,"line":1770},[1894],{"type":40,"tag":467,"props":1895,"children":1896},{"emptyLinePlaceholder":1332},[1897],{"type":45,"value":1335},{"type":40,"tag":467,"props":1899,"children":1900},{"class":469,"line":1779},[1901],{"type":40,"tag":467,"props":1902,"children":1903},{},[1904],{"type":45,"value":1905},"-- Next page (pass last id from previous result as $last_id):\n",{"type":40,"tag":467,"props":1907,"children":1908},{"class":469,"line":23},[1909],{"type":40,"tag":467,"props":1910,"children":1911},{},[1912],{"type":45,"value":1913},"SELECT id, title FROM posts WHERE id \u003C $last_id ORDER BY id DESC LIMIT 10;\n",{"type":40,"tag":48,"props":1915,"children":1916},{},[1917],{"type":45,"value":1918},"For filtered queries, include the filter column in the index alongside id:",{"type":40,"tag":457,"props":1920,"children":1922},{"className":459,"code":1921,"language":22,"meta":461,"style":461},"-- Query: WHERE category = 'news' ORDER BY id DESC\nCREATE INDEX idx_cat_id ON posts (category, id);\n-- Cursor query:\nSELECT id, title FROM posts WHERE category = 'news' AND id \u003C $last_id ORDER BY id DESC LIMIT 10;\n",[1923],{"type":40,"tag":73,"props":1924,"children":1925},{"__ignoreMap":461},[1926,1934,1942,1950],{"type":40,"tag":467,"props":1927,"children":1928},{"class":469,"line":470},[1929],{"type":40,"tag":467,"props":1930,"children":1931},{},[1932],{"type":45,"value":1933},"-- Query: WHERE category = 'news' ORDER BY id DESC\n",{"type":40,"tag":467,"props":1935,"children":1936},{"class":469,"line":27},[1937],{"type":40,"tag":467,"props":1938,"children":1939},{},[1940],{"type":45,"value":1941},"CREATE INDEX idx_cat_id ON posts (category, id);\n",{"type":40,"tag":467,"props":1943,"children":1944},{"class":469,"line":637},[1945],{"type":40,"tag":467,"props":1946,"children":1947},{},[1948],{"type":45,"value":1949},"-- Cursor query:\n",{"type":40,"tag":467,"props":1951,"children":1952},{"class":469,"line":982},[1953],{"type":40,"tag":467,"props":1954,"children":1955},{},[1956],{"type":45,"value":1957},"SELECT id, title FROM posts WHERE category = 'news' AND id \u003C $last_id ORDER BY id DESC LIMIT 10;\n",{"type":40,"tag":48,"props":1959,"children":1960},{},[1961,1963,1969],{"type":45,"value":1962},"To detect whether another page exists, fetch ",{"type":40,"tag":73,"props":1964,"children":1966},{"className":1965},[],[1967],{"type":45,"value":1968},"LIMIT 11",{"type":45,"value":1970}," and check if the 11th row appears.",{"type":40,"tag":112,"props":1972,"children":1974},{"id":1973},"histogram-statistics",[1975],{"type":45,"value":1976},"Histogram Statistics",{"type":40,"tag":48,"props":1978,"children":1979},{},[1980],{"type":45,"value":1981},"Histograms let the optimizer understand data distribution on non-indexed columns — critical for query plan quality on complex queries. Without them, the optimizer assumes uniform distribution and can choose wrong join orders.",{"type":40,"tag":457,"props":1983,"children":1985},{"className":459,"code":1984,"language":22,"meta":461,"style":461},"-- Collect histograms for a table (requires a full scan — run during low traffic):\nANALYZE TABLE orders;\n\n-- Verify histograms were collected:\nSELECT * FROM mysql.column_stats WHERE table_name = 'orders';\n",[1986],{"type":40,"tag":73,"props":1987,"children":1988},{"__ignoreMap":461},[1989,1997,2005,2012,2020],{"type":40,"tag":467,"props":1990,"children":1991},{"class":469,"line":470},[1992],{"type":40,"tag":467,"props":1993,"children":1994},{},[1995],{"type":45,"value":1996},"-- Collect histograms for a table (requires a full scan — run during low traffic):\n",{"type":40,"tag":467,"props":1998,"children":1999},{"class":469,"line":27},[2000],{"type":40,"tag":467,"props":2001,"children":2002},{},[2003],{"type":45,"value":2004},"ANALYZE TABLE orders;\n",{"type":40,"tag":467,"props":2006,"children":2007},{"class":469,"line":637},[2008],{"type":40,"tag":467,"props":2009,"children":2010},{"emptyLinePlaceholder":1332},[2011],{"type":45,"value":1335},{"type":40,"tag":467,"props":2013,"children":2014},{"class":469,"line":982},[2015],{"type":40,"tag":467,"props":2016,"children":2017},{},[2018],{"type":45,"value":2019},"-- Verify histograms were collected:\n",{"type":40,"tag":467,"props":2021,"children":2022},{"class":469,"line":1338},[2023],{"type":40,"tag":467,"props":2024,"children":2025},{},[2026],{"type":45,"value":2027},"SELECT * FROM mysql.column_stats WHERE table_name = 'orders';\n",{"type":40,"tag":48,"props":2029,"children":2030},{},[2031],{"type":40,"tag":65,"props":2032,"children":2033},{},[2034,2036,2041],{"type":45,"value":2035},"When to run ",{"type":40,"tag":73,"props":2037,"children":2039},{"className":2038},[],[2040],{"type":45,"value":235},{"type":45,"value":909},{"type":40,"tag":1015,"props":2043,"children":2044},{},[2045,2050,2069],{"type":40,"tag":1019,"props":2046,"children":2047},{},[2048],{"type":45,"value":2049},"After bulk inserts or large data changes",{"type":40,"tag":1019,"props":2051,"children":2052},{},[2053,2055,2060,2062,2067],{"type":45,"value":2054},"When ",{"type":40,"tag":73,"props":2056,"children":2058},{"className":2057},[],[2059],{"type":45,"value":343},{"type":45,"value":2061}," shows unexpectedly high ",{"type":40,"tag":73,"props":2063,"children":2065},{"className":2064},[],[2066],{"type":45,"value":774},{"type":45,"value":2068}," estimates",{"type":40,"tag":1019,"props":2070,"children":2071},{},[2072],{"type":45,"value":2073},"After initially creating a table and loading data",{"type":40,"tag":48,"props":2075,"children":2076},{},[2077,2082],{"type":40,"tag":65,"props":2078,"children":2079},{},[2080],{"type":45,"value":2081},"Tune histogram granularity",{"type":45,"value":2083}," for tables with highly skewed data distributions:",{"type":40,"tag":457,"props":2085,"children":2087},{"className":459,"code":2086,"language":22,"meta":461,"style":461},"SET histogram_size = 100;  -- default is 0 (disabled) in older versions, 254 in 10.4.3+\nANALYZE TABLE orders;\n",[2088],{"type":40,"tag":73,"props":2089,"children":2090},{"__ignoreMap":461},[2091,2099],{"type":40,"tag":467,"props":2092,"children":2093},{"class":469,"line":470},[2094],{"type":40,"tag":467,"props":2095,"children":2096},{},[2097],{"type":45,"value":2098},"SET histogram_size = 100;  -- default is 0 (disabled) in older versions, 254 in 10.4.3+\n",{"type":40,"tag":467,"props":2100,"children":2101},{"class":469,"line":27},[2102],{"type":40,"tag":467,"props":2103,"children":2104},{},[2105],{"type":45,"value":2004},{"type":40,"tag":48,"props":2107,"children":2108},{},[2109,2111,2116,2118,2124,2126,2132,2134,2140],{"type":45,"value":2110},"Histograms are collected per-column automatically when using ",{"type":40,"tag":73,"props":2112,"children":2114},{"className":2113},[],[2115],{"type":45,"value":235},{"type":45,"value":2117}," with ",{"type":40,"tag":73,"props":2119,"children":2121},{"className":2120},[],[2122],{"type":45,"value":2123},"histogram_size > 0",{"type":45,"value":2125},". They are stored in ",{"type":40,"tag":73,"props":2127,"children":2129},{"className":2128},[],[2130],{"type":45,"value":2131},"mysql.column_stats",{"type":45,"value":2133}," and consulted when ",{"type":40,"tag":73,"props":2135,"children":2137},{"className":2136},[],[2138],{"type":45,"value":2139},"optimizer_use_condition_selectivity >= 4",{"type":45,"value":2141}," (default in 10.4.1+).",{"type":40,"tag":112,"props":2143,"children":2145},{"id":2144},"mariadb-optimizer-switches",[2146],{"type":45,"value":2147},"MariaDB Optimizer Switches",{"type":40,"tag":48,"props":2149,"children":2150},{},[2151],{"type":45,"value":2152},"MariaDB's optimizer has more tunable flags than MySQL. The most useful for developers:",{"type":40,"tag":457,"props":2154,"children":2156},{"className":459,"code":2155,"language":22,"meta":461,"style":461},"-- See current settings:\nSELECT @@optimizer_switch\\G\n\n-- Disable a specific optimization for a session (useful for debugging):\nSET optimizer_switch = 'derived_merge=off';\n\n-- Re-enable:\nSET optimizer_switch = 'derived_merge=on';\n",[2157],{"type":40,"tag":73,"props":2158,"children":2159},{"__ignoreMap":461},[2160,2168,2176,2183,2191,2199,2206,2214],{"type":40,"tag":467,"props":2161,"children":2162},{"class":469,"line":470},[2163],{"type":40,"tag":467,"props":2164,"children":2165},{},[2166],{"type":45,"value":2167},"-- See current settings:\n",{"type":40,"tag":467,"props":2169,"children":2170},{"class":469,"line":27},[2171],{"type":40,"tag":467,"props":2172,"children":2173},{},[2174],{"type":45,"value":2175},"SELECT @@optimizer_switch\\G\n",{"type":40,"tag":467,"props":2177,"children":2178},{"class":469,"line":637},[2179],{"type":40,"tag":467,"props":2180,"children":2181},{"emptyLinePlaceholder":1332},[2182],{"type":45,"value":1335},{"type":40,"tag":467,"props":2184,"children":2185},{"class":469,"line":982},[2186],{"type":40,"tag":467,"props":2187,"children":2188},{},[2189],{"type":45,"value":2190},"-- Disable a specific optimization for a session (useful for debugging):\n",{"type":40,"tag":467,"props":2192,"children":2193},{"class":469,"line":1338},[2194],{"type":40,"tag":467,"props":2195,"children":2196},{},[2197],{"type":45,"value":2198},"SET optimizer_switch = 'derived_merge=off';\n",{"type":40,"tag":467,"props":2200,"children":2201},{"class":469,"line":1347},[2202],{"type":40,"tag":467,"props":2203,"children":2204},{"emptyLinePlaceholder":1332},[2205],{"type":45,"value":1335},{"type":40,"tag":467,"props":2207,"children":2208},{"class":469,"line":1770},[2209],{"type":40,"tag":467,"props":2210,"children":2211},{},[2212],{"type":45,"value":2213},"-- Re-enable:\n",{"type":40,"tag":467,"props":2215,"children":2216},{"class":469,"line":1779},[2217],{"type":40,"tag":467,"props":2218,"children":2219},{},[2220],{"type":45,"value":2221},"SET optimizer_switch = 'derived_merge=on';\n",{"type":40,"tag":48,"props":2223,"children":2224},{},[2225],{"type":40,"tag":65,"props":2226,"children":2227},{},[2228],{"type":45,"value":2229},"Most impactful flags:",{"type":40,"tag":119,"props":2231,"children":2232},{},[2233,2254],{"type":40,"tag":123,"props":2234,"children":2235},{},[2236],{"type":40,"tag":127,"props":2237,"children":2238},{},[2239,2244,2249],{"type":40,"tag":131,"props":2240,"children":2241},{},[2242],{"type":45,"value":2243},"Flag",{"type":40,"tag":131,"props":2245,"children":2246},{},[2247],{"type":45,"value":2248},"Default",{"type":40,"tag":131,"props":2250,"children":2251},{},[2252],{"type":45,"value":2253},"Effect",{"type":40,"tag":142,"props":2255,"children":2256},{},[2257,2279,2315,2336,2357],{"type":40,"tag":127,"props":2258,"children":2259},{},[2260,2269,2274],{"type":40,"tag":149,"props":2261,"children":2262},{},[2263],{"type":40,"tag":73,"props":2264,"children":2266},{"className":2265},[],[2267],{"type":45,"value":2268},"derived_merge",{"type":40,"tag":149,"props":2270,"children":2271},{},[2272],{"type":45,"value":2273},"on",{"type":40,"tag":149,"props":2275,"children":2276},{},[2277],{"type":45,"value":2278},"Merges derived tables into outer query — usually faster",{"type":40,"tag":127,"props":2280,"children":2281},{},[2282,2291,2295],{"type":40,"tag":149,"props":2283,"children":2284},{},[2285],{"type":40,"tag":73,"props":2286,"children":2288},{"className":2287},[],[2289],{"type":45,"value":2290},"semijoin",{"type":40,"tag":149,"props":2292,"children":2293},{},[2294],{"type":45,"value":2273},{"type":40,"tag":149,"props":2296,"children":2297},{},[2298,2300,2306,2307,2313],{"type":45,"value":2299},"Optimizes ",{"type":40,"tag":73,"props":2301,"children":2303},{"className":2302},[],[2304],{"type":45,"value":2305},"IN",{"type":45,"value":1213},{"type":40,"tag":73,"props":2308,"children":2310},{"className":2309},[],[2311],{"type":45,"value":2312},"EXISTS",{"type":45,"value":2314}," subqueries — disable to debug unexpected plans",{"type":40,"tag":127,"props":2316,"children":2317},{},[2318,2327,2331],{"type":40,"tag":149,"props":2319,"children":2320},{},[2321],{"type":40,"tag":73,"props":2322,"children":2324},{"className":2323},[],[2325],{"type":45,"value":2326},"subquery_cache",{"type":40,"tag":149,"props":2328,"children":2329},{},[2330],{"type":45,"value":2273},{"type":40,"tag":149,"props":2332,"children":2333},{},[2334],{"type":45,"value":2335},"Caches correlated subquery results — big win for repeated subqueries",{"type":40,"tag":127,"props":2337,"children":2338},{},[2339,2348,2352],{"type":40,"tag":149,"props":2340,"children":2341},{},[2342],{"type":40,"tag":73,"props":2343,"children":2345},{"className":2344},[],[2346],{"type":45,"value":2347},"rowid_filter",{"type":40,"tag":149,"props":2349,"children":2350},{},[2351],{"type":45,"value":2273},{"type":40,"tag":149,"props":2353,"children":2354},{},[2355],{"type":45,"value":2356},"Pre-filters rowids before fetching rows — helps range queries",{"type":40,"tag":127,"props":2358,"children":2359},{},[2360,2369,2374],{"type":40,"tag":149,"props":2361,"children":2362},{},[2363],{"type":40,"tag":73,"props":2364,"children":2366},{"className":2365},[],[2367],{"type":45,"value":2368},"mrr",{"type":40,"tag":149,"props":2370,"children":2371},{},[2372],{"type":45,"value":2373},"off",{"type":40,"tag":149,"props":2375,"children":2376},{},[2377],{"type":45,"value":2378},"Multi-Range Read — enable for large range scans on spinning disks",{"type":40,"tag":48,"props":2380,"children":2381},{},[2382],{"type":45,"value":2383},"Turn flags off one at a time to isolate which optimization is causing a bad plan, then report via JIRA if a default setting produces a worse plan than the alternative.",{"type":40,"tag":996,"props":2385,"children":2387},{"id":2386},"optimizer-improvements-in-the-1071011-lts-window",[2388],{"type":45,"value":2389},"Optimizer Improvements in the 10.7–10.11 LTS Window",{"type":40,"tag":48,"props":2391,"children":2392},{},[2393],{"type":45,"value":2394},"The 10.11 LTS line bundles features that arrived in the 10.7–10.10 short-term releases:",{"type":40,"tag":1015,"props":2396,"children":2397},{},[2398,2415,2456,2478,2496],{"type":40,"tag":1019,"props":2399,"children":2400},{},[2401,2406,2408,2413],{"type":40,"tag":65,"props":2402,"children":2403},{},[2404],{"type":45,"value":2405},"JSON-format histograms",{"type":45,"value":2407}," (10.8+, MDEV-21130, MDEV-26519) — histogram statistics are stored in JSON and are more precise than the older binary format. Just running ",{"type":40,"tag":73,"props":2409,"children":2411},{"className":2410},[],[2412],{"type":45,"value":235},{"type":45,"value":2414}," on 10.8+ gives the optimizer better cardinality estimates.",{"type":40,"tag":1019,"props":2416,"children":2417},{},[2418,2423,2425,2431,2433,2439,2441,2447,2448,2454],{"type":40,"tag":65,"props":2419,"children":2420},{},[2421],{"type":45,"value":2422},"Descending indexes",{"type":45,"value":2424}," (10.8+, MDEV-13756) — ",{"type":40,"tag":73,"props":2426,"children":2428},{"className":2427},[],[2429],{"type":45,"value":2430},"CREATE INDEX idx ON t (a ASC, b DESC)",{"type":45,"value":2432}," is supported; useful for composite ",{"type":40,"tag":73,"props":2434,"children":2436},{"className":2435},[],[2437],{"type":45,"value":2438},"ORDER BY a, b DESC",{"type":45,"value":2440}," patterns and for ",{"type":40,"tag":73,"props":2442,"children":2444},{"className":2443},[],[2445],{"type":45,"value":2446},"MIN()",{"type":45,"value":1213},{"type":40,"tag":73,"props":2449,"children":2451},{"className":2450},[],[2452],{"type":45,"value":2453},"MAX()",{"type":45,"value":2455}," on descending indexes.",{"type":40,"tag":1019,"props":2457,"children":2458},{},[2459,2468,2470,2476],{"type":40,"tag":65,"props":2460,"children":2461},{},[2462],{"type":40,"tag":73,"props":2463,"children":2465},{"className":2464},[],[2466],{"type":45,"value":2467},"SHOW ANALYZE [FORMAT=JSON]",{"type":45,"value":2469}," (10.9+, MDEV-27021) — get the optimizer plan and runtime stats for a query running in another connection without intrusion. ",{"type":40,"tag":73,"props":2471,"children":2473},{"className":2472},[],[2474],{"type":45,"value":2475},"EXPLAIN FOR CONNECTION",{"type":45,"value":2477}," syntax also supported (MDEV-10000).",{"type":40,"tag":1019,"props":2479,"children":2480},{},[2481,2494],{"type":40,"tag":65,"props":2482,"children":2483},{},[2484,2486,2492],{"type":45,"value":2485},"Improved optimization for joins with many ",{"type":40,"tag":73,"props":2487,"children":2489},{"className":2488},[],[2490],{"type":45,"value":2491},"eq_ref",{"type":45,"value":2493}," tables",{"type":45,"value":2495}," (10.10+, MDEV-28852, MDEV-26278) — large star-schema-style joins plan dramatically better.",{"type":40,"tag":1019,"props":2497,"children":2498},{},[2499,2510],{"type":40,"tag":65,"props":2500,"children":2501},{},[2502,2508],{"type":40,"tag":73,"props":2503,"children":2505},{"className":2504},[],[2506],{"type":45,"value":2507},"ANALYZE FORMAT=JSON",{"type":45,"value":2509}," reports time spent in the optimizer itself",{"type":45,"value":2511}," (10.11+, MDEV-28926) — separates planning time from execution time.",{"type":40,"tag":996,"props":2513,"children":2515},{"id":2514},"optimizer-improvements-in-114-lts",[2516],{"type":45,"value":2517},"Optimizer Improvements in 11.4 LTS",{"type":40,"tag":48,"props":2519,"children":2520},{},[2521],{"type":45,"value":2522},"The 11.4 LTS line continues the overhaul:",{"type":40,"tag":1015,"props":2524,"children":2525},{},[2526,2551,2593,2624],{"type":40,"tag":1019,"props":2527,"children":2528},{},[2529,2534,2536,2541,2543,2549],{"type":40,"tag":65,"props":2530,"children":2531},{},[2532],{"type":45,"value":2533},"New cost-based cost model",{"type":45,"value":2535}," (11.0+) — replaces the older rule-based heuristics with a tuned model aware of SSDs and per-engine characteristics. ",{"type":40,"tag":73,"props":2537,"children":2539},{"className":2538},[],[2540],{"type":45,"value":343},{"type":45,"value":2542}," and join-order choices in 10.6 vs. 11.4 can differ noticeably on the same query. If you have manual ",{"type":40,"tag":73,"props":2544,"children":2546},{"className":2545},[],[2547],{"type":45,"value":2548},"optimizer_adjust_secondary_key_costs",{"type":45,"value":2550}," settings from 10.x, remove them — they're no-ops on 11.4+.",{"type":40,"tag":1019,"props":2552,"children":2553},{},[2554,2570,2572,2577,2578,2583,2585,2591],{"type":40,"tag":65,"props":2555,"children":2556},{},[2557,2559,2564,2565],{"type":45,"value":2558},"Semi-join optimization for single-table ",{"type":40,"tag":73,"props":2560,"children":2562},{"className":2561},[],[2563],{"type":45,"value":1255},{"type":45,"value":1213},{"type":40,"tag":73,"props":2566,"children":2568},{"className":2567},[],[2569],{"type":45,"value":1262},{"type":45,"value":2571}," (11.1+, MDEV-7487) — subqueries inside ",{"type":40,"tag":73,"props":2573,"children":2575},{"className":2574},[],[2576],{"type":45,"value":1255},{"type":45,"value":1213},{"type":40,"tag":73,"props":2579,"children":2581},{"className":2580},[],[2582],{"type":45,"value":1262},{"type":45,"value":2584}," can now use the same subquery rewrites that ",{"type":40,"tag":73,"props":2586,"children":2588},{"className":2587},[],[2589],{"type":45,"value":2590},"SELECT",{"type":45,"value":2592}," uses (materialization, semi-join, etc.). Often a large speedup, no rewrite needed.",{"type":40,"tag":1019,"props":2594,"children":2595},{},[2596,2616,2618,2622],{"type":40,"tag":65,"props":2597,"children":2598},{},[2599,2601,2607,2608,2614],{"type":45,"value":2600},"Sargable ",{"type":40,"tag":73,"props":2602,"children":2604},{"className":2603},[],[2605],{"type":45,"value":2606},"DATE",{"type":45,"value":1213},{"type":40,"tag":73,"props":2609,"children":2611},{"className":2610},[],[2612],{"type":45,"value":2613},"YEAR",{"type":45,"value":2615}," comparisons against constants",{"type":45,"value":2617}," (11.1+, MDEV-8320) — see ",{"type":40,"tag":201,"props":2619,"children":2620},{"href":203},[2621],{"type":45,"value":1372},{"type":45,"value":2623}," above.",{"type":40,"tag":1019,"props":2625,"children":2626},{},[2627,2632,2634,2639,2641,2647,2648,2654,2655,2661,2662,2668],{"type":40,"tag":65,"props":2628,"children":2629},{},[2630],{"type":45,"value":2631},"Sargable case-folding",{"type":45,"value":2633}," (11.3+, MDEV-31496, ",{"type":40,"tag":73,"props":2635,"children":2637},{"className":2636},[],[2638],{"type":45,"value":1628},{"type":45,"value":2640}," on by default) — ",{"type":40,"tag":73,"props":2642,"children":2644},{"className":2643},[],[2645],{"type":45,"value":2646},"UCASE",{"type":45,"value":1213},{"type":40,"tag":73,"props":2649,"children":2651},{"className":2650},[],[2652],{"type":45,"value":2653},"LCASE",{"type":45,"value":1213},{"type":40,"tag":73,"props":2656,"children":2658},{"className":2657},[],[2659],{"type":45,"value":2660},"UPPER",{"type":45,"value":1213},{"type":40,"tag":73,"props":2663,"children":2665},{"className":2664},[],[2666],{"type":45,"value":2667},"LOWER",{"type":45,"value":2669}," on a column with a case-insensitive collation can use the index.",{"type":40,"tag":996,"props":2671,"children":2673},{"id":2672},"optimizer-improvements-in-115118-lts",[2674],{"type":45,"value":2675},"Optimizer Improvements in 11.5–11.8 LTS",{"type":40,"tag":48,"props":2677,"children":2678},{},[2679],{"type":45,"value":2680},"These are part of the current LTS baseline — useful for understanding what the optimizer can do today:",{"type":40,"tag":1015,"props":2682,"children":2683},{},[2684,2694,2709,2719,2740,2759],{"type":40,"tag":1019,"props":2685,"children":2686},{},[2687,2692],{"type":40,"tag":65,"props":2688,"children":2689},{},[2690],{"type":45,"value":2691},"Index Condition Pushdown on partitioned tables",{"type":45,"value":2693}," (11.5+, MDEV-12404) — previously partitioned tables couldn't use ICP; now they do, often a large speedup on partitioned schemas",{"type":40,"tag":1019,"props":2695,"children":2696},{},[2697,2707],{"type":40,"tag":65,"props":2698,"children":2699},{},[2700,2705],{"type":40,"tag":73,"props":2701,"children":2703},{"className":2702},[],[2704],{"type":45,"value":78},{"type":45,"value":2706}," shows selectivity of pushed index condition",{"type":45,"value":2708}," (11.5+, MDEV-18478) — useful when diagnosing whether ICP is helping",{"type":40,"tag":1019,"props":2710,"children":2711},{},[2712,2717],{"type":40,"tag":65,"props":2713,"children":2714},{},[2715],{"type":45,"value":2716},"Charset Narrowing Optimization on by default",{"type":45,"value":2718}," (11.8+, MDEV-34380) — eliminates unnecessary character set conversions in WHERE clauses",{"type":40,"tag":1019,"props":2720,"children":2721},{},[2722,2733,2735],{"type":40,"tag":65,"props":2723,"children":2724},{},[2725,2731],{"type":40,"tag":73,"props":2726,"children":2728},{"className":2727},[],[2729],{"type":45,"value":2730},"SUBSTR(col, 1, n) = const_str",{"type":45,"value":2732}," optimization",{"type":45,"value":2734}," (11.8+, MDEV-34911) — the optimizer can now use a column index even when the condition is a leading-prefix ",{"type":40,"tag":73,"props":2736,"children":2738},{"className":2737},[],[2739],{"type":45,"value":1516},{"type":40,"tag":1019,"props":2741,"children":2742},{},[2743,2748,2750,2757],{"type":40,"tag":65,"props":2744,"children":2745},{},[2746],{"type":45,"value":2747},"Virtual column support in the optimizer",{"type":45,"value":2749}," (11.8+, MDEV-35616) — see ",{"type":40,"tag":201,"props":2751,"children":2754},{"href":2752,"rel":2753},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fvirtual-column-support-in-the-optimizer",[355],[2755],{"type":45,"value":2756},"Virtual Column Support in the Optimizer",{"type":45,"value":2758},"; previously, virtual columns were largely invisible to the optimizer",{"type":40,"tag":1019,"props":2760,"children":2761},{},[2762,2778],{"type":40,"tag":65,"props":2763,"children":2764},{},[2765,2767,2772,2773],{"type":45,"value":2766},"Cost-based subquery strategy for single-table ",{"type":40,"tag":73,"props":2768,"children":2770},{"className":2769},[],[2771],{"type":45,"value":1255},{"type":45,"value":1213},{"type":40,"tag":73,"props":2774,"children":2776},{"className":2775},[],[2777],{"type":45,"value":1262},{"type":45,"value":2779}," (11.8+, MDEV-25008) — the optimizer now picks between subquery strategies by cost",{"type":40,"tag":996,"props":2781,"children":2783},{"id":2782},"optimizer-improvements-in-mariadb-12x",[2784],{"type":45,"value":2785},"Optimizer Improvements in MariaDB 12.x",{"type":40,"tag":48,"props":2787,"children":2788},{},[2789],{"type":45,"value":2790},"Several further limitations were lifted in the 12.x rolling releases:",{"type":40,"tag":1015,"props":2792,"children":2793},{},[2794,2812,2822,2848,2858,2876],{"type":40,"tag":1019,"props":2795,"children":2796},{},[2797,2802,2804,2810],{"type":40,"tag":65,"props":2798,"children":2799},{},[2800],{"type":45,"value":2801},"Rowid filtering on reverse-ordered scans",{"type":45,"value":2803}," (12.0+) — previously ",{"type":40,"tag":73,"props":2805,"children":2807},{"className":2806},[],[2808],{"type":45,"value":2809},"ORDER BY ... DESC",{"type":45,"value":2811}," queries couldn't benefit from rowid filtering; now they can",{"type":40,"tag":1019,"props":2813,"children":2814},{},[2815,2820],{"type":40,"tag":65,"props":2816,"children":2817},{},[2818],{"type":45,"value":2819},"Index Condition Pushdown on reverse-ordered scans",{"type":45,"value":2821}," (12.0+) — same fix for ICP",{"type":40,"tag":1019,"props":2823,"children":2824},{},[2825,2838,2840,2846],{"type":40,"tag":65,"props":2826,"children":2827},{},[2828,2830,2836],{"type":45,"value":2829},"Loose Index Scan (\"Use index for group-by\") works with ",{"type":40,"tag":73,"props":2831,"children":2833},{"className":2832},[],[2834],{"type":45,"value":2835},"DESC",{"type":45,"value":2837}," key parts",{"type":45,"value":2839}," (12.0+) — previously required ",{"type":40,"tag":73,"props":2841,"children":2843},{"className":2842},[],[2844],{"type":45,"value":2845},"ASC",{"type":45,"value":2847}," indexes",{"type":40,"tag":1019,"props":2849,"children":2850},{},[2851,2856],{"type":40,"tag":65,"props":2852,"children":2853},{},[2854],{"type":45,"value":2855},"GROUP BY \u002F ORDER BY can use indexes on virtual columns",{"type":45,"value":2857}," (12.1+)",{"type":40,"tag":1019,"props":2859,"children":2860},{},[2861,2866,2868,2874],{"type":40,"tag":65,"props":2862,"children":2863},{},[2864],{"type":45,"value":2865},"Reorderable LEFT JOIN optimization",{"type":45,"value":2867}," (12.3+) — the optimizer can now reorder more ",{"type":40,"tag":73,"props":2869,"children":2871},{"className":2870},[],[2872],{"type":45,"value":2873},"LEFT JOIN",{"type":45,"value":2875}," combinations",{"type":40,"tag":1019,"props":2877,"children":2878},{},[2879,2884,2886,2891],{"type":40,"tag":65,"props":2880,"children":2881},{},[2882],{"type":45,"value":2883},"Distinct GROUP BY column inference",{"type":45,"value":2885}," (12.2+) — derived tables with ",{"type":40,"tag":73,"props":2887,"children":2889},{"className":2888},[],[2890],{"type":45,"value":841},{"type":45,"value":2892}," are recognized as having distinct group keys, enabling more optimizations downstream",{"type":40,"tag":48,"props":2894,"children":2895},{},[2896],{"type":45,"value":2897},"If you target the 11.8 LTS baseline and see a plan that looks needlessly slow on a reverse-ordered or virtual-column query, it may be one of these — verify by running the same query on a 12.x version.",{"type":40,"tag":112,"props":2899,"children":2901},{"id":2900},"optimizer-hints",[2902],{"type":45,"value":2903},"Optimizer Hints",{"type":40,"tag":48,"props":2905,"children":2906},{},[2907,2909,2915,2917,2922],{"type":45,"value":2908},"MariaDB 12.0 introduced a comprehensive MySQL-8-style optimizer hints framework (MDEV-35504), with additional hints added through 12.1 and 12.2. Hints go in a ",{"type":40,"tag":73,"props":2910,"children":2912},{"className":2911},[],[2913],{"type":45,"value":2914},"\u002F*+ ... *\u002F",{"type":45,"value":2916}," comment right after ",{"type":40,"tag":73,"props":2918,"children":2920},{"className":2919},[],[2921],{"type":45,"value":2590},{"type":45,"value":2923}," and override the optimizer for one query without changing session settings:",{"type":40,"tag":457,"props":2925,"children":2927},{"className":459,"code":2926,"language":22,"meta":461,"style":461},"SELECT \u002F*+ JOIN_ORDER(o, c) *\u002F *\nFROM orders o JOIN customers c ON c.id = o.customer_id;\n",[2928],{"type":40,"tag":73,"props":2929,"children":2930},{"__ignoreMap":461},[2931,2939],{"type":40,"tag":467,"props":2932,"children":2933},{"class":469,"line":470},[2934],{"type":40,"tag":467,"props":2935,"children":2936},{},[2937],{"type":45,"value":2938},"SELECT \u002F*+ JOIN_ORDER(o, c) *\u002F *\n",{"type":40,"tag":467,"props":2940,"children":2941},{"class":469,"line":27},[2942],{"type":40,"tag":467,"props":2943,"children":2944},{},[2945],{"type":45,"value":2946},"FROM orders o JOIN customers c ON c.id = o.customer_id;\n",{"type":40,"tag":48,"props":2948,"children":2949},{},[2950],{"type":40,"tag":65,"props":2951,"children":2952},{},[2953],{"type":45,"value":2954},"Available hints:",{"type":40,"tag":119,"props":2956,"children":2957},{},[2958,2978],{"type":40,"tag":123,"props":2959,"children":2960},{},[2961],{"type":40,"tag":127,"props":2962,"children":2963},{},[2964,2969,2973],{"type":40,"tag":131,"props":2965,"children":2966},{},[2967],{"type":45,"value":2968},"Hint",{"type":40,"tag":131,"props":2970,"children":2971},{},[2972],{"type":45,"value":1407},{"type":40,"tag":131,"props":2974,"children":2975},{},[2976],{"type":45,"value":2977},"Purpose",{"type":40,"tag":142,"props":2979,"children":2980},{},[2981,3003,3046,3074,3095,3130,3151,3172,3200,3243,3278],{"type":40,"tag":127,"props":2982,"children":2983},{},[2984,2993,2998],{"type":40,"tag":149,"props":2985,"children":2986},{},[2987],{"type":40,"tag":73,"props":2988,"children":2990},{"className":2989},[],[2991],{"type":45,"value":2992},"QB_NAME(name)",{"type":40,"tag":149,"props":2994,"children":2995},{},[2996],{"type":45,"value":2997},"12.0",{"type":40,"tag":149,"props":2999,"children":3000},{},[3001],{"type":45,"value":3002},"Name a query block so other hints can target it from outside",{"type":40,"tag":127,"props":3004,"children":3005},{},[3006,3023,3027],{"type":40,"tag":149,"props":3007,"children":3008},{},[3009,3015,3017],{"type":40,"tag":73,"props":3010,"children":3012},{"className":3011},[],[3013],{"type":45,"value":3014},"JOIN_FIXED_ORDER",{"type":45,"value":3016}," \u002F ",{"type":40,"tag":73,"props":3018,"children":3020},{"className":3019},[],[3021],{"type":45,"value":3022},"JOIN_ORDER(t1, t2, ...)",{"type":40,"tag":149,"props":3024,"children":3025},{},[3026],{"type":45,"value":2997},{"type":40,"tag":149,"props":3028,"children":3029},{},[3030,3032,3037,3039,3045],{"type":45,"value":3031},"Force a join order (",{"type":40,"tag":73,"props":3033,"children":3035},{"className":3034},[],[3036],{"type":45,"value":3014},{"type":45,"value":3038}," is similar to ",{"type":40,"tag":73,"props":3040,"children":3042},{"className":3041},[],[3043],{"type":45,"value":3044},"STRAIGHT_JOIN",{"type":45,"value":1475},{"type":40,"tag":127,"props":3047,"children":3048},{},[3049,3065,3069],{"type":40,"tag":149,"props":3050,"children":3051},{},[3052,3058,3059],{"type":40,"tag":73,"props":3053,"children":3055},{"className":3054},[],[3056],{"type":45,"value":3057},"JOIN_PREFIX(t1, ...)",{"type":45,"value":3016},{"type":40,"tag":73,"props":3060,"children":3062},{"className":3061},[],[3063],{"type":45,"value":3064},"JOIN_SUFFIX(t1, ...)",{"type":40,"tag":149,"props":3066,"children":3067},{},[3068],{"type":45,"value":2997},{"type":40,"tag":149,"props":3070,"children":3071},{},[3072],{"type":45,"value":3073},"Force specific tables to be first or last in the join order",{"type":40,"tag":127,"props":3075,"children":3076},{},[3077,3086,3090],{"type":40,"tag":149,"props":3078,"children":3079},{},[3080],{"type":40,"tag":73,"props":3081,"children":3083},{"className":3082},[],[3084],{"type":45,"value":3085},"MAX_EXECUTION_TIME(ms)",{"type":40,"tag":149,"props":3087,"children":3088},{},[3089],{"type":45,"value":2997},{"type":40,"tag":149,"props":3091,"children":3092},{},[3093],{"type":45,"value":3094},"Abort the query if it runs longer than the timeout",{"type":40,"tag":127,"props":3096,"children":3097},{},[3098,3121,3125],{"type":40,"tag":149,"props":3099,"children":3100},{},[3101,3107,3108,3114,3115],{"type":40,"tag":73,"props":3102,"children":3104},{"className":3103},[],[3105],{"type":45,"value":3106},"[NO_]MRR",{"type":45,"value":3016},{"type":40,"tag":73,"props":3109,"children":3111},{"className":3110},[],[3112],{"type":45,"value":3113},"[NO_]BKA",{"type":45,"value":3016},{"type":40,"tag":73,"props":3116,"children":3118},{"className":3117},[],[3119],{"type":45,"value":3120},"[NO_]BNL",{"type":40,"tag":149,"props":3122,"children":3123},{},[3124],{"type":45,"value":2997},{"type":40,"tag":149,"props":3126,"children":3127},{},[3128],{"type":45,"value":3129},"Toggle Multi-Range Read, Batched Key Access, Block Nested Loop",{"type":40,"tag":127,"props":3131,"children":3132},{},[3133,3142,3146],{"type":40,"tag":149,"props":3134,"children":3135},{},[3136],{"type":40,"tag":73,"props":3137,"children":3139},{"className":3138},[],[3140],{"type":45,"value":3141},"[NO_]ICP",{"type":40,"tag":149,"props":3143,"children":3144},{},[3145],{"type":45,"value":2997},{"type":40,"tag":149,"props":3147,"children":3148},{},[3149],{"type":45,"value":3150},"Toggle Index Condition Pushdown",{"type":40,"tag":127,"props":3152,"children":3153},{},[3154,3163,3167],{"type":40,"tag":149,"props":3155,"children":3156},{},[3157],{"type":40,"tag":73,"props":3158,"children":3160},{"className":3159},[],[3161],{"type":45,"value":3162},"[NO_]RANGE_OPTIMIZATION",{"type":40,"tag":149,"props":3164,"children":3165},{},[3166],{"type":45,"value":2997},{"type":40,"tag":149,"props":3168,"children":3169},{},[3170],{"type":45,"value":3171},"Toggle range optimizer",{"type":40,"tag":127,"props":3173,"children":3174},{},[3175,3191,3195],{"type":40,"tag":149,"props":3176,"children":3177},{},[3178,3184,3185],{"type":40,"tag":73,"props":3179,"children":3181},{"className":3180},[],[3182],{"type":45,"value":3183},"SEMIJOIN(strategy, ...)",{"type":45,"value":3016},{"type":40,"tag":73,"props":3186,"children":3188},{"className":3187},[],[3189],{"type":45,"value":3190},"SUBQUERY(strategy)",{"type":40,"tag":149,"props":3192,"children":3193},{},[3194],{"type":45,"value":2997},{"type":40,"tag":149,"props":3196,"children":3197},{},[3198],{"type":45,"value":3199},"Pick subquery rewrite strategy",{"type":40,"tag":127,"props":3201,"children":3202},{},[3203,3233,3238],{"type":40,"tag":149,"props":3204,"children":3205},{},[3206,3212,3213,3219,3220,3226,3227],{"type":40,"tag":73,"props":3207,"children":3209},{"className":3208},[],[3210],{"type":45,"value":3211},"[NO_]INDEX(t idx, ...)",{"type":45,"value":3016},{"type":40,"tag":73,"props":3214,"children":3216},{"className":3215},[],[3217],{"type":45,"value":3218},"[NO_]JOIN_INDEX",{"type":45,"value":3016},{"type":40,"tag":73,"props":3221,"children":3223},{"className":3222},[],[3224],{"type":45,"value":3225},"[NO_]GROUP_INDEX",{"type":45,"value":3016},{"type":40,"tag":73,"props":3228,"children":3230},{"className":3229},[],[3231],{"type":45,"value":3232},"[NO_]ORDER_INDEX",{"type":40,"tag":149,"props":3234,"children":3235},{},[3236],{"type":45,"value":3237},"12.1",{"type":40,"tag":149,"props":3239,"children":3240},{},[3241],{"type":45,"value":3242},"Force \u002F forbid specific index usage by purpose",{"type":40,"tag":127,"props":3244,"children":3245},{},[3246,3269,3273],{"type":40,"tag":149,"props":3247,"children":3248},{},[3249,3255,3256,3262,3263],{"type":40,"tag":73,"props":3250,"children":3252},{"className":3251},[],[3253],{"type":45,"value":3254},"[NO_]SPLIT_MATERIALIZED",{"type":45,"value":3016},{"type":40,"tag":73,"props":3257,"children":3259},{"className":3258},[],[3260],{"type":45,"value":3261},"[NO_]DERIVED_CONDITION_PUSHDOWN",{"type":45,"value":3016},{"type":40,"tag":73,"props":3264,"children":3266},{"className":3265},[],[3267],{"type":45,"value":3268},"[NO_]MERGE",{"type":40,"tag":149,"props":3270,"children":3271},{},[3272],{"type":45,"value":3237},{"type":40,"tag":149,"props":3274,"children":3275},{},[3276],{"type":45,"value":3277},"Control subquery \u002F derived-table optimizations",{"type":40,"tag":127,"props":3279,"children":3280},{},[3281,3297,3302],{"type":40,"tag":149,"props":3282,"children":3283},{},[3284,3290,3291],{"type":40,"tag":73,"props":3285,"children":3287},{"className":3286},[],[3288],{"type":45,"value":3289},"[NO_]ROWID_FILTER",{"type":45,"value":3016},{"type":40,"tag":73,"props":3292,"children":3294},{"className":3293},[],[3295],{"type":45,"value":3296},"[NO_]INDEX_MERGE",{"type":40,"tag":149,"props":3298,"children":3299},{},[3300],{"type":45,"value":3301},"12.2",{"type":40,"tag":149,"props":3303,"children":3304},{},[3305],{"type":45,"value":3306},"Toggle rowid filtering and index merge",{"type":40,"tag":48,"props":3308,"children":3309},{},[3310,3321],{"type":40,"tag":65,"props":3311,"children":3312},{},[3313,3319],{"type":40,"tag":73,"props":3314,"children":3316},{"className":3315},[],[3317],{"type":45,"value":3318},"QB_NAME()",{"type":45,"value":3320}," example",{"type":45,"value":3322}," — name a subquery so an outer hint can target it:",{"type":40,"tag":457,"props":3324,"children":3326},{"className":459,"code":3325,"language":22,"meta":461,"style":461},"SELECT \u002F*+ NO_MERGE(@sub) *\u002F *\nFROM (\n    SELECT \u002F*+ QB_NAME(sub) *\u002F customer_id, COUNT(*) AS n\n    FROM orders\n    GROUP BY customer_id\n) t\nWHERE n > 10;\n",[3327],{"type":40,"tag":73,"props":3328,"children":3329},{"__ignoreMap":461},[3330,3338,3346,3354,3362,3370,3378],{"type":40,"tag":467,"props":3331,"children":3332},{"class":469,"line":470},[3333],{"type":40,"tag":467,"props":3334,"children":3335},{},[3336],{"type":45,"value":3337},"SELECT \u002F*+ NO_MERGE(@sub) *\u002F *\n",{"type":40,"tag":467,"props":3339,"children":3340},{"class":469,"line":27},[3341],{"type":40,"tag":467,"props":3342,"children":3343},{},[3344],{"type":45,"value":3345},"FROM (\n",{"type":40,"tag":467,"props":3347,"children":3348},{"class":469,"line":637},[3349],{"type":40,"tag":467,"props":3350,"children":3351},{},[3352],{"type":45,"value":3353},"    SELECT \u002F*+ QB_NAME(sub) *\u002F customer_id, COUNT(*) AS n\n",{"type":40,"tag":467,"props":3355,"children":3356},{"class":469,"line":982},[3357],{"type":40,"tag":467,"props":3358,"children":3359},{},[3360],{"type":45,"value":3361},"    FROM orders\n",{"type":40,"tag":467,"props":3363,"children":3364},{"class":469,"line":1338},[3365],{"type":40,"tag":467,"props":3366,"children":3367},{},[3368],{"type":45,"value":3369},"    GROUP BY customer_id\n",{"type":40,"tag":467,"props":3371,"children":3372},{"class":469,"line":1347},[3373],{"type":40,"tag":467,"props":3374,"children":3375},{},[3376],{"type":45,"value":3377},") t\n",{"type":40,"tag":467,"props":3379,"children":3380},{"class":469,"line":1770},[3381],{"type":40,"tag":467,"props":3382,"children":3383},{},[3384],{"type":45,"value":3385},"WHERE n > 10;\n",{"type":40,"tag":48,"props":3387,"children":3388},{},[3389,3391,3397],{"type":45,"value":3390},"Hints are more targeted than ",{"type":40,"tag":73,"props":3392,"children":3394},{"className":3393},[],[3395],{"type":45,"value":3396},"SET optimizer_switch",{"type":45,"value":3398}," because they apply only to the query they're in, not the whole session.",{"type":40,"tag":112,"props":3400,"children":3402},{"id":3401},"bounding-expensive-queries-limit-rows-examined",[3403],{"type":45,"value":3404},"Bounding Expensive Queries: LIMIT ROWS EXAMINED",{"type":40,"tag":48,"props":3406,"children":3407},{},[3408,3414,3416,3421,3423,3428],{"type":40,"tag":73,"props":3409,"children":3411},{"className":3410},[],[3412],{"type":45,"value":3413},"LIMIT ROWS EXAMINED",{"type":45,"value":3415}," is a ",{"type":40,"tag":65,"props":3417,"children":3418},{},[3419],{"type":45,"value":3420},"MariaDB-specific",{"type":45,"value":3422}," extension (since 5.5.21) with no MySQL equivalent. It caps how many rows a ",{"type":40,"tag":73,"props":3424,"children":3426},{"className":3425},[],[3427],{"type":45,"value":2590},{"type":45,"value":3429}," may examine, terminating execution early once the cap is hit — a safety valve against runaway scans on unbounded or ad-hoc queries:",{"type":40,"tag":457,"props":3431,"children":3433},{"className":459,"code":3432,"language":22,"meta":461,"style":461},"-- Up to 10 result rows, but stop after examining 10,000 rows:\nSELECT * FROM t1, t2 LIMIT 10 ROWS EXAMINED 10000;\n\n-- The cap can be used on its own:\nSELECT * FROM big_table WHERE status = 'x' LIMIT ROWS EXAMINED 50000;\n",[3434],{"type":40,"tag":73,"props":3435,"children":3436},{"__ignoreMap":461},[3437,3445,3453,3460,3468],{"type":40,"tag":467,"props":3438,"children":3439},{"class":469,"line":470},[3440],{"type":40,"tag":467,"props":3441,"children":3442},{},[3443],{"type":45,"value":3444},"-- Up to 10 result rows, but stop after examining 10,000 rows:\n",{"type":40,"tag":467,"props":3446,"children":3447},{"class":469,"line":27},[3448],{"type":40,"tag":467,"props":3449,"children":3450},{},[3451],{"type":45,"value":3452},"SELECT * FROM t1, t2 LIMIT 10 ROWS EXAMINED 10000;\n",{"type":40,"tag":467,"props":3454,"children":3455},{"class":469,"line":637},[3456],{"type":40,"tag":467,"props":3457,"children":3458},{"emptyLinePlaceholder":1332},[3459],{"type":45,"value":1335},{"type":40,"tag":467,"props":3461,"children":3462},{"class":469,"line":982},[3463],{"type":40,"tag":467,"props":3464,"children":3465},{},[3466],{"type":45,"value":3467},"-- The cap can be used on its own:\n",{"type":40,"tag":467,"props":3469,"children":3470},{"class":469,"line":1338},[3471],{"type":40,"tag":467,"props":3472,"children":3473},{},[3474],{"type":45,"value":3475},"SELECT * FROM big_table WHERE status = 'x' LIMIT ROWS EXAMINED 50000;\n",{"type":40,"tag":48,"props":3477,"children":3478},{},[3479,3481,3486,3488,3493,3495,3500,3501,3506,3508,3513,3515,3521],{"type":45,"value":3480},"When the cap is reached the query returns a ",{"type":40,"tag":65,"props":3482,"children":3483},{},[3484],{"type":45,"value":3485},"partial result set",{"type":45,"value":3487}," plus a warning — so it is a guard rail, not a way to get correct-but-faster answers. ",{"type":40,"tag":73,"props":3489,"children":3491},{"className":3490},[],[3492],{"type":45,"value":2590},{"type":45,"value":3494}," only; it is a syntax error on ",{"type":40,"tag":73,"props":3496,"children":3498},{"className":3497},[],[3499],{"type":45,"value":1255},{"type":45,"value":1213},{"type":40,"tag":73,"props":3502,"children":3504},{"className":3503},[],[3505],{"type":45,"value":1262},{"type":45,"value":3507},". For a time-based bound instead, use the ",{"type":40,"tag":73,"props":3509,"children":3511},{"className":3510},[],[3512],{"type":45,"value":3085},{"type":45,"value":3514}," optimizer hint (12.0+) above. See ",{"type":40,"tag":201,"props":3516,"children":3519},{"href":3517,"rel":3518},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Flimit-rows-examined",[355],[3520],{"type":45,"value":3413},{"type":45,"value":1366},{"type":40,"tag":112,"props":3523,"children":3525},{"id":3524},"quick-wins-checklist",[3526],{"type":45,"value":3527},"Quick Wins Checklist",{"type":40,"tag":48,"props":3529,"children":3530},{},[3531],{"type":45,"value":3532},"Before adding indexes or rewriting queries, check these first:",{"type":40,"tag":3534,"props":3535,"children":3536},"ol",{},[3537,3555,3565,3575,3616,3628,3633],{"type":40,"tag":1019,"props":3538,"children":3539},{},[3540,3542,3547,3549],{"type":45,"value":3541},"Confirm ",{"type":40,"tag":73,"props":3543,"children":3545},{"className":3544},[],[3546],{"type":45,"value":399},{"type":45,"value":3548}," at startup (restart required if off) — ",{"type":40,"tag":201,"props":3550,"children":3552},{"href":353,"rel":3551},[355],[3553],{"type":45,"value":3554},"Performance Schema Overview",{"type":40,"tag":1019,"props":3556,"children":3557},{},[3558,3563],{"type":40,"tag":73,"props":3559,"children":3561},{"className":3560},[],[3562],{"type":45,"value":343},{"type":45,"value":3564}," the slow query — confirm where the time actually is",{"type":40,"tag":1019,"props":3566,"children":3567},{},[3568,3573],{"type":40,"tag":73,"props":3569,"children":3571},{"className":3570},[],[3572],{"type":45,"value":235},{"type":45,"value":3574}," — stale statistics cause bad plans",{"type":40,"tag":1019,"props":3576,"children":3577},{},[3578,3580,3586,3588,3594,3595,3601,3602,3608,3609,3614],{"type":45,"value":3579},"Check for functions on indexed columns in ",{"type":40,"tag":73,"props":3581,"children":3583},{"className":3582},[],[3584],{"type":45,"value":3585},"WHERE",{"type":45,"value":3587}," — note many cases are now sargable on 11.4+ (",{"type":40,"tag":73,"props":3589,"children":3591},{"className":3590},[],[3592],{"type":45,"value":3593},"YEAR()",{"type":45,"value":1249},{"type":40,"tag":73,"props":3596,"children":3598},{"className":3597},[],[3599],{"type":45,"value":3600},"DATE()",{"type":45,"value":1249},{"type":40,"tag":73,"props":3603,"children":3605},{"className":3604},[],[3606],{"type":45,"value":3607},"UPPER()",{"type":45,"value":1805},{"type":40,"tag":73,"props":3610,"children":3612},{"className":3611},[],[3613],{"type":45,"value":1636},{"type":45,"value":3615}," collations)",{"type":40,"tag":1019,"props":3617,"children":3618},{},[3619,3621,3626],{"type":45,"value":3620},"Check for ",{"type":40,"tag":73,"props":3622,"children":3624},{"className":3623},[],[3625],{"type":45,"value":168},{"type":45,"value":3627}," in pagination queries",{"type":40,"tag":1019,"props":3629,"children":3630},{},[3631],{"type":45,"value":3632},"Verify composite index column order matches query predicates (leftmost prefix)",{"type":40,"tag":1019,"props":3634,"children":3635},{},[3636,3638,3643,3645,3650,3651,3656],{"type":45,"value":3637},"Check ",{"type":40,"tag":73,"props":3639,"children":3641},{"className":3640},[],[3642],{"type":45,"value":343},{"type":45,"value":3644}," Extra column for ",{"type":40,"tag":73,"props":3646,"children":3648},{"className":3647},[],[3649],{"type":45,"value":805},{"type":45,"value":843},{"type":40,"tag":73,"props":3652,"children":3654},{"className":3653},[],[3655],{"type":45,"value":830},{"type":45,"value":3657}," — these often point to a missing or misordered index",{"type":40,"tag":112,"props":3659,"children":3661},{"id":3660},"sources",[3662],{"type":45,"value":3663},"Sources",{"type":40,"tag":1015,"props":3665,"children":3666},{},[3667,3677,3686,3696,3706,3716,3726,3736],{"type":40,"tag":1019,"props":3668,"children":3669},{},[3670],{"type":40,"tag":201,"props":3671,"children":3674},{"href":3672,"rel":3673},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations",[355],[3675],{"type":45,"value":3676},"Query Optimizations — MariaDB Docs",{"type":40,"tag":1019,"props":3678,"children":3679},{},[3680],{"type":40,"tag":201,"props":3681,"children":3683},{"href":353,"rel":3682},[355],[3684],{"type":45,"value":3685},"Performance Schema Overview — MariaDB Docs",{"type":40,"tag":1019,"props":3687,"children":3688},{},[3689],{"type":40,"tag":201,"props":3690,"children":3693},{"href":3691,"rel":3692},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Freference\u002Fsql-statements\u002Fadministrative-sql-statements\u002Fanalyze-and-explain-statements\u002Fexplain",[355],[3694],{"type":45,"value":3695},"EXPLAIN — MariaDB Docs",{"type":40,"tag":1019,"props":3697,"children":3698},{},[3699],{"type":40,"tag":201,"props":3700,"children":3703},{"href":3701,"rel":3702},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Foptimizer-switch",[355],[3704],{"type":45,"value":3705},"optimizer_switch — MariaDB Docs",{"type":40,"tag":1019,"props":3707,"children":3708},{},[3709],{"type":40,"tag":201,"props":3710,"children":3713},{"href":3711,"rel":3712},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fmariadb-quickstart-guides\u002Fmariadb-indexes-guide",[355],[3714],{"type":45,"value":3715},"Getting Started with Indexes — MariaDB Docs",{"type":40,"tag":1019,"props":3717,"children":3718},{},[3719],{"type":40,"tag":201,"props":3720,"children":3723},{"href":3721,"rel":3722},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Foptimization-and-indexes\u002Fbuilding-the-best-index-for-a-given-select",[355],[3724],{"type":45,"value":3725},"Building the Best Index for a Given SELECT — MariaDB Docs",{"type":40,"tag":1019,"props":3727,"children":3728},{},[3729],{"type":40,"tag":201,"props":3730,"children":3733},{"href":3731,"rel":3732},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fstatistics-for-optimizing-queries\u002Fhistogram-based-statistics",[355],[3734],{"type":45,"value":3735},"Histogram-Based Statistics — MariaDB Docs",{"type":40,"tag":1019,"props":3737,"children":3738},{},[3739],{"type":40,"tag":201,"props":3740,"children":3743},{"href":3741,"rel":3742},"https:\u002F\u002Fmariadb.com\u002Fdocs\u002Fserver\u002Fha-and-performance\u002Foptimization-and-tuning\u002Fquery-optimizations\u002Fpagination-optimization",[355],[3744],{"type":45,"value":3745},"Pagination Optimization — MariaDB Docs",{"type":40,"tag":48,"props":3747,"children":3748},{},[3749],{"type":40,"tag":52,"props":3750,"children":3751},{},[3752,3754,3761],{"type":45,"value":3753},"For topics not covered here, see the official MariaDB documentation at ",{"type":40,"tag":201,"props":3755,"children":3758},{"href":3756,"rel":3757},"https:\u002F\u002Fmariadb.com\u002Fdocs",[355],[3759],{"type":45,"value":3760},"mariadb.com\u002Fdocs",{"type":45,"value":1366},{"type":40,"tag":3763,"props":3764,"children":3765},"style",{},[3766],{"type":45,"value":3767},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3769,"total":1779},[3770,3781,3793,3800,3812,3830,3842,3855],{"slug":3771,"name":3771,"fn":3772,"description":3773,"org":3774,"tags":3775,"stars":23,"repoUrl":24,"updatedAt":3780},"mariadb-features","optimize and manage MariaDB databases","MariaDB-specific features and capabilities that go beyond standard MySQL. Use when evaluating MariaDB, optimizing an existing MariaDB application, reviewing code or schema for MariaDB improvements, asking what MariaDB can do that other databases cannot, or migrating from Oracle to MariaDB. Also use when the user asks what could be improved in how a codebase uses MariaDB, or asks about MariaDB advantages over MySQL or PostgreSQL.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3776,3777,3778,3779],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":21,"slug":22,"type":15},"2026-07-16T06:01:55.988338",{"slug":3782,"name":3782,"fn":3783,"description":3784,"org":3785,"tags":3786,"stars":23,"repoUrl":24,"updatedAt":3792},"mariadb-mcp","connect AI agents to MariaDB","How to connect AI agents to MariaDB using the Model Context Protocol (MCP). Use when setting up MCP with MariaDB, connecting Claude Code, Cursor, or other AI tools to a MariaDB database, enabling natural language database queries, or building AI applications that need live database access. The MariaDB MCP Server lets agents query schemas, run read-only SQL, and perform semantic search against MariaDB.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3787,3788,3789],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3790,"slug":3791,"type":15},"MCP","mcp","2026-07-13T06:14:00.682655",{"slug":4,"name":4,"fn":5,"description":6,"org":3794,"tags":3795,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3796,3797,3798,3799],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":21,"slug":22,"type":15},{"slug":3801,"name":3801,"fn":3802,"description":3803,"org":3804,"tags":3805,"stars":23,"repoUrl":24,"updatedAt":3811},"mariadb-replication-and-ha","configure MariaDB replication and high availability","Best practices for MariaDB replication and high availability — Galera Cluster, GTID replication, semi-synchronous replication, parallel replication, and application patterns for HA environments. Use when setting up replication, designing applications for HA, working with Galera Cluster, asking about MariaDB GTID, handling replication lag in application code, or choosing between replication topologies. IMPORTANT — MariaDB GTID format is incompatible with MySQL GTID, and Galera Cluster needs no server plugin to load but does require the separate galera wsrep provider library (galera-4).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3806,3809,3810],{"name":3807,"slug":3808,"type":15},"Architecture","architecture",{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},"2026-07-13T06:14:13.989369",{"slug":3813,"name":3813,"fn":3814,"description":3815,"org":3816,"tags":3817,"stars":23,"repoUrl":24,"updatedAt":3829},"mariadb-system-versioned-tables","implement MariaDB system-versioned tables","Best practices for MariaDB system-versioned (temporal) tables — automatic row history built into the database. Use when tracking data changes over time, implementing audit trails, meeting GDPR or compliance requirements, doing point-in-time queries, or when the user asks about row history, data versioning, temporal tables, or querying past data states in MariaDB. This feature is unique to MariaDB among MySQL-compatible databases.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3818,3821,3824,3825,3828],{"name":3819,"slug":3820,"type":15},"Audit","audit",{"name":3822,"slug":3823,"type":15},"Compliance","compliance",{"name":18,"slug":19,"type":15},{"name":3826,"slug":3827,"type":15},"GDPR","gdpr",{"name":9,"slug":8,"type":15},"2026-07-13T06:14:16.779878",{"slug":3831,"name":3831,"fn":3832,"description":3833,"org":3834,"tags":3835,"stars":23,"repoUrl":24,"updatedAt":3841},"mariadb-vector","build semantic search with MariaDB vectors","Best practices for using vectors and AI with MariaDB. Use when writing SQL involving VECTOR columns, building RAG or semantic search with MariaDB, choosing embedding models, designing vector indexes, or integrating MariaDB with AI frameworks like LangChain, LlamaIndex, or Spring AI. Also use when the user mentions MariaDB and any of: vectors, embeddings, similarity search, nearest neighbor, AI, RAG, or LLM. IMPORTANT — MariaDB has native built-in vector support since version 11.7; it is NOT a plugin or extension (unlike pgvector for PostgreSQL). Do not recommend installing any extension.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3836,3837,3838],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3839,"slug":3840,"type":15},"Migration","migration","2026-07-13T06:14:01.939479",{"slug":3843,"name":3843,"fn":3844,"description":3845,"org":3846,"tags":3847,"stars":23,"repoUrl":24,"updatedAt":3854},"mysql-to-mariadb","migrate applications from MySQL to MariaDB","Compatibility guide for developers moving from MySQL to MariaDB, and for developers with MySQL experience working with MariaDB. Use when migrating a MySQL application to MariaDB, when MySQL syntax or habits cause unexpected behavior in MariaDB, when asking about MySQL\u002FMariaDB compatibility, or when adapting code written for MySQL to run on MariaDB. IMPORTANT — MariaDB diverges significantly from MySQL 8.0 and is not a simple drop-in replacement for modern MySQL. Authentication plugins, JSON handling, GTID replication, and several SQL features differ in important ways.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3848,3849,3850,3851],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3839,"slug":3840,"type":15},{"name":3852,"slug":3853,"type":15},"MySQL","mysql","2026-07-13T06:14:08.675338",{"slug":3856,"name":3856,"fn":3857,"description":3858,"org":3859,"tags":3860,"stars":23,"repoUrl":24,"updatedAt":3864},"oracle-to-mariadb","migrate Oracle databases to MariaDB","Compatibility guide for developers migrating from Oracle Database to MariaDB. Use when migrating Oracle schemas, PL\u002FSQL procedures, or applications to MariaDB, when Oracle syntax causes unexpected behavior in MariaDB, or when evaluating MariaDB as an Oracle replacement. MariaDB is the only open source database with native PL\u002FSQL compatibility — MariaDB's sql_mode=ORACLE enables migration of approximately 80% of Oracle code without rewrites.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3861,3862,3863],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3839,"slug":3840,"type":15},"2026-07-13T06:14:11.069809",{"items":3866,"total":1779},[3867,3874,3880,3887,3893,3901,3907],{"slug":3771,"name":3771,"fn":3772,"description":3773,"org":3868,"tags":3869,"stars":23,"repoUrl":24,"updatedAt":3780},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3870,3871,3872,3873],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":21,"slug":22,"type":15},{"slug":3782,"name":3782,"fn":3783,"description":3784,"org":3875,"tags":3876,"stars":23,"repoUrl":24,"updatedAt":3792},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3877,3878,3879],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3790,"slug":3791,"type":15},{"slug":4,"name":4,"fn":5,"description":6,"org":3881,"tags":3882,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3883,3884,3885,3886],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":21,"slug":22,"type":15},{"slug":3801,"name":3801,"fn":3802,"description":3803,"org":3888,"tags":3889,"stars":23,"repoUrl":24,"updatedAt":3811},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3890,3891,3892],{"name":3807,"slug":3808,"type":15},{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"slug":3813,"name":3813,"fn":3814,"description":3815,"org":3894,"tags":3895,"stars":23,"repoUrl":24,"updatedAt":3829},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3896,3897,3898,3899,3900],{"name":3819,"slug":3820,"type":15},{"name":3822,"slug":3823,"type":15},{"name":18,"slug":19,"type":15},{"name":3826,"slug":3827,"type":15},{"name":9,"slug":8,"type":15},{"slug":3831,"name":3831,"fn":3832,"description":3833,"org":3902,"tags":3903,"stars":23,"repoUrl":24,"updatedAt":3841},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3904,3905,3906],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3839,"slug":3840,"type":15},{"slug":3843,"name":3843,"fn":3844,"description":3845,"org":3908,"tags":3909,"stars":23,"repoUrl":24,"updatedAt":3854},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[3910,3911,3912,3913],{"name":18,"slug":19,"type":15},{"name":9,"slug":8,"type":15},{"name":3839,"slug":3840,"type":15},{"name":3852,"slug":3853,"type":15}]