High Performance
SQLite
Introduction
Introduction to this course
Introduction to SQLite
SQLite is safe
It's just a file
Running SQLite locally
Good uses for SQLite
SQLite's limitations
The documentation
SQLite Internals
SQLite's structure
SQLite's file format
Dot commands
Pragmas
Virtual tables
Schema
Flexible types
Types
Strict types
Dates
Booleans
Floating point
Rowid tables
Auto increments
Without rowid
Generated columns
Optimizing SQLite
Locking
Rollback mode
WAL mode
WAL vs Journal benchmarks
Busy timeout
Transaction modes
Vacuum
Analyze & Optimize
Suggested pragmas
Faster inserts
Indexes
Introduction to indexes
B+ trees
Primary, secondary, and clustered indexes
Without rowid tables
Benchmarking without rowid tables
Imposter tables
Primary key data types
Where to add indexes
Index selectivity
Composite indexes
Composite ordering
Covering indexes
Partial indexes
Indexes on expressions
Automatic indexes
Duplicate indexes
Indexing joins
Advanced SQL
Explain
Index obfuscation
Joins
Subqueries
Unions
CTEs
Recursive CTEs
Window functions
Dealing with NULLs
Row value syntax
Indexed sorting
Upserts
Returning
Aggregates
Triggers
Operating SQLite
Altering schema
Altering schema with tools
Multi-database
Multi-tenancy
Backups
Exports
How to corrupt SQLite
Advanced JSON
Intro to JSON
JSON vs. JSONB
Argument types: path, value, JSON
JSON5
Valid JSON
Creating JSON objects + arrays
JSON Extraction
Updating JSON
JSON aggregates
JSON table functions
Indexing JSON
Full Text Search
Creating FTS tables
Performing searches
Ranking results
Highlighting matches
Bonus Interviews
DHH discusses SQLite in Ruby on Rails
Distributed SQLite with Litestream and LiteFS
Offline-first, multiplayer SQLite
Production SQLite with Turso and libSQL
Migrating from Postgres to SQLite with Kent C. Dodds
Ruby on Rails with SQLite
Moving from Redis to SQLite with Mike Buckbee
Locked video

Please purchase the course to watch this video.

Video thumbnail
Indexes
Composite ordering

Full Course

$
179
$229
USD, one-time fee
High Performance SQLite helped level up our local-first React Native apps, taking full advantage of the database features and squeezing out the best performance.
Dwight Watson
Dwight Watson

SQLite for Production

Build with and integrate SQLite into your production applications.

Test Data

I've made my test data available for you to use and follow along.

Download
or
Use on Turso

Summary

In the video, I explain how using an index in SQLite can optimize the way we order query results. I discuss that once we've unlocked certain parts of an index, such as first and last names, we can then order by these fields without needing a temporary b-tree. I demonstrate that we should follow the rule of left to right without skipping, ensuring efficient querying and ordering.

Video Transcript

Left to right no skipping stops at the first range. You thought you were free, it's gonna come back to haunt you over and over and over. Once you unlock part of an index, you can use it for anything. So if we had select star from users where first name equals Aaron, now we have access to first name and to last name to do ordering. So if we were to order by last name descending, let's put a throw a limit on that.

You'll see search using index multi first name equals question mark. But we don't see last name in there so how do we know how do we know that last name, was How do we know that the index was used to order by last name? Well, unfortunately, it doesn't tell us that but we can, we can kinda back into it. So instead of doing by last name, let's order by birthday. And according to our rules, birthday is not accessible because it's got that last name in the middle.

We got first name, last name and then birthday and we're trying to use birthday. There you go. Using a temp b tree for order by. So in this case, SQLite is telling us, man, I wasn't able to order it straight out of the index, so I'm gonna construct my own b tree. If we were to do this again and use something that's not in the index at all, let's just do created at, you'll see the exact same thing.

Use temp b tree for order by. This means that once and, last name equals Francis, this means that once the birthday is unlocked we can then order by it, order by birthday descending. And you see that temporary b tree is gone. So we've put a strict equality on first name and on last name and now we're able to order by first name, last name, or birthday. And in this case, we chose birthday.

So let's try this again and say last name is less than Francis which is a little bit silly but, it's good for this demonstration. So we'll say order by last name. You see, it's still not using that temporary b tree because we've unlocked the ability to use last name out of the index and so it's just going to order by in fact, it's already ordered. The data is already ordered over in the index and so it's just gonna read it out of the index. Left to right, no skipping.

Always the rule. And once an index part is unlocked or has become available, you can use that for ordering and you still get to use the index advantaged method rather than constructing the temporary b tree. So remember, left to right, no skipping stops at the first range. Once those parts are free, you can use them for ordering.