DEV Community

Cover image for Inside SQLite’s Frontend: Join Table Ordering
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

Inside SQLite’s Frontend: Join Table Ordering

Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.

Even if your WHERE clause is perfectly optimized, a bad join order can still make your query slow.

How SQLite Executes Joins

SQLite uses a very simple but effective strategy for joins.

It always executes joins as nested loops.

That means for a query like:

SELECT * FROM A JOIN B;
Enter fullscreen mode Exit fullscreen mode

SQLite will do something like:

for each row in A:
    for each row in B:
        process the combination
Enter fullscreen mode Exit fullscreen mode

The important detail here is that the order of tables determines how these loops are nested.

  • The first table becomes the outer loop
  • The last table becomes the inner loop

So the order in your FROM clause directly affects execution.

Why Order Matters

Nested loops can be very expensive if the outer loop has too many rows.

For example, if table A has 1 million rows and table B has 1 million rows:

  • A outer → B inner = 1M × 1M operations
  • B outer → A inner = also large, but may differ depending on indexes

The goal is to reduce the number of iterations as early as possible.

SQLite Doesn’t Always Follow Your Order

Although the default behavior follows the FROM clause order, SQLite can reorder tables if it finds a better execution plan.

It uses a greedy algorithm to decide the order.

Instead of trying all possible combinations, it builds the order step by step:

  • First, pick the table that is cheapest to process
  • Then pick the next cheapest
  • Continue until all tables are placed

If two options are equally good, SQLite falls back to the original order in the query.

What “Cheapest” Means

SQLite estimates cost using several factors:

  • Availability of indexes
  • How selective those indexes are
  • Whether sorting can be avoided
  • Estimated number of rows to scan

For example:

  • An index that reduces 1 million rows to 1 row is extremely valuable
  • An index that reduces 1 million rows to 900,000 rows is not very useful

This is where the ANALYZE command becomes important. It collects statistics so SQLite can better estimate how effective an index is.

Index Nested Loop Joins

If a table has an index on the join column, SQLite often places it as the inner loop.

This allows efficient lookups for each row from the outer loop.

This strategy is called an index nested loop join.

Instead of scanning the entire inner table, SQLite uses the index to quickly find matching rows.

Special Cases: INNER vs OUTER Joins

Inner joins are flexible.

SQLite can freely reorder tables in inner joins because the result does not depend on order.

Outer joins are different.

A LEFT OUTER JOIN is not commutative, meaning order matters for correctness. Because of this, SQLite does not reorder outer joins.

However, tables involved in inner joins around an outer join may still be reordered if it improves performance.

WHERE Clause Integration

If you use ON or USING clauses in joins, SQLite internally converts them into additional WHERE clause conditions before optimization.

This means all the WHERE clause optimizations you saw earlier still apply here.

Forcing Join Order

In most cases, SQLite’s automatic reordering works well and you do not need to worry about it.

But if you want to force a specific order, you can use a CROSS JOIN.

Example:

SELECT * FROM table1 CROSS JOIN table2;
Enter fullscreen mode Exit fullscreen mode

Here:

  • table1 will always be the outer loop
  • table2 will always be the inner loop

This gives you manual control when needed.

In the next part, we will look at index selection, where SQLite decides exactly which index to use when multiple options are available.

git-lrc
*AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.*

Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.

⭐ Star it on GitHub:

GitHub logo HexmosTech / git-lrc

Free, Unlimited AI Code Reviews That Run on Commit




AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.

See It In Action

See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements

git-lrc-intro-60s.mp4

Why

  • 🤖 AI agents silently break things. Code removed. Logic changed. Edge cases gone. You won't notice until production.
  • 🔍 Catch it before it ships. AI-powered inline comments show you exactly what changed and what looks wrong.
  • 🔁 Build a

Top comments (0)