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
Schema
Flexible types

Full Course

$
179
$229
USD, one-time fee
High Performance SQLite is an excellent and immersive course, featuring real-time typed commands and valuable edge case explanations. I highly recommend it for enhancing your SQLite skills.
Han-Hsun Liu
Han-Hsun Liu

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 this module, I started building tables in SQLite and explored its unique data type system. SQLite uses "flexible typing," allowing columns to hold various data types, which can be powerful for certain situations like handling mixed data or CSV files. Despite declaring column types, SQLite applies data types at the cell level, meaning you can mix data types in a single column, which can be both advantageous and inconvenient.

Video Transcript

We're going to start building out some tables in SQLite. We've looked at the history, internals, and how SQLite works under the hood, which I think is very interesting and helpful as we move forward. Now, we'll get to start working with SQLite directly.

If you're coming from a MySQL or PostgreSQL background, some of these concepts will be surprising. Namely, SQLite has a different approach to data types, which they refer to as "flexible typing."

Flexible Typing in SQLite

Historically, SQLite has not been strongly typed. You could say it's "weakly typed," but the SQLite team prefers the term "flexible typing." This means that you can create a table with no data types, and SQLite will gladly accept and store any type of data in the columns.

For example, we can create a table called ex with no data types specified:

CREATE TABLE ex(a, b, c);
INSERT INTO ex VALUES (1, 'asdf', 3);
INSERT INTO ex VALUES ('asdf', 2, 'asdf');
SELECT * FROM ex;

In this case, the data types are intermingled within the columns, but SQLite will still store the data safely without any data loss.

This flexible typing can be valuable in certain situations, such as:

  • Handling CSV data with "dirty" or mixed data types
  • Implementing an entity-attribute-value (EAV) pattern
  • Using SQLite as a key-value store where the keys and values can be of any type

However, this flexibility can also be problematic in some cases, which is where the concept of "strict typing" comes into play.

Strict Typing in SQLite

Let's create another table, ex2, with specified data types:

CREATE TABLE ex2 (
  a INTEGER,
  b TEXT
);

INSERT INTO ex2 VALUES (1, 'hello');
INSERT INTO ex2 VALUES ('hello', 2);

Even though we've declared the data types, SQLite will still allow us to insert data that doesn't match the specified types. When we query the table, we can see that SQLite tries to maintain the types as best it can:

SELECT a, typeof(a), b, typeof(b) FROM ex2;

This shows that the integer value 1 is stored as an integer, but the string 'hello' is stored as text in the a column.

The key takeaway is that in default SQLite tables, the data type is applied at the cell level, not the column level. This means you can have a mix of data types within a single column.

SQLite also has a concept of "type affinity," which we'll explore in the next video. This is how SQLite tries to manage the flexible typing and maintain data integrity as best it can.