generated from btholt/next-course-starter
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
183 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
This one is controversial but SQLite is not rigid at all about what data it will store in what columns. It really only has four data types, and it then it coerces all of the allowed SQL data types into those data types. | ||
|
||
| Column Datatype | Types Allowed In That Column | | ||
| --------------- | ---------------------------- | | ||
| INTEGER | INTEGER, REAL, TEXT, BLOB | | ||
| REAL | REAL, TEXT, BLOB | | ||
| TEXT | TEXT, BLOB | | ||
| BLOB | INTEGER, REAL, TEXT, BLOB | | ||
|
||
What is indeed nice about this is that SQLite will take most SQL queries written for other databases (like MySQL, Postgres, etc.) and it will work for SQLite as SQLite will just coerce most things to a TEXT data type. | ||
|
||
A common one in other databases is VARCHAR and SQLite will happily accept that and just make it a text field. VARCHAR usually comes with a text limit (like this field can only be 255 characters long) and SQLite will not respect those limits. So you can create a table with VARCHAR(255) and then just insert a whole page's worth of text into it, SQLite does not care. | ||
|
||
That said, SQLite did add a STRICT table feature in 2021 that allows SQLite to be slightly more mindful of types. However the core strongly believes this to be not the case. | ||
|
||
If you want to read more, [the core team wrote their thoughts out here][sqlite]. | ||
|
||
## Lacked data types | ||
|
||
Critically, there is no date type which can prove challenging sometimes. You'll either store some sort of date standard string of just UNIX time. | ||
|
||
There's also no Boolean. You'll represent these as INTEGERS 0 and 1. TRUE and FALSE are just aliases of 0 and 1. | ||
|
||
[sqlite]: https://www.sqlite.org/flextypegood.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
title: "Limits of SQLite" | ||
--- | ||
|
||
SQLite has unique limits in what it can and can't do. Nearly all of them are overly generous and you should _never_ hit their ceiling and if you do, you are doing something wrong. | ||
|
||
## Row size | ||
|
||
Max length of text: 1GB | ||
|
||
Each row can be a 1 GB of size. If you're reaching anything remotely close to this, you need a different storage strategy, probably using something like [S3][s3] to store large object and then store the metadata using SQLite. | ||
|
||
## Columns on a table | ||
|
||
Max amount of columns on a table: 2,000 (and up to 32,000) columns | ||
|
||
You can have 2,000 columns on a table but man, you can probably architect your data differently if you have 2,000 columns. A JSON column could help a lot or just move to a document based database like MongoDB. | ||
|
||
If you want to, you can recompile SQLite yourself and remove the limit and have up to 32,767 columns but please, please do not do that. | ||
|
||
## Length of SQL query | ||
|
||
Max length of a SQL query, 1,000,000,000 characters | ||
|
||
Look, if you can write a query that long, I'm just in awe. At that point you're just coding your whole app as SQL. | ||
|
||
## Tables in a join | ||
|
||
Max number of tables in a join: 64 tables | ||
|
||
This actually feels like one you _could_ hit though it'd be weird. SQLite uses 8 bytes to do its lookup table for joins and therefore it has a hard limit of 64 tables that it can reference. If you have a query doing 64 joins, you can rearchitect your data to not need so many joins or just do two queries. | ||
|
||
## Length of LIKE terms | ||
|
||
Max length of LIKE globs: 50,000 characters | ||
|
||
Write "globs" (or the terms you give to LIKE) can have some perfomance implications if they're too long so they limt these to 50,000 characters. Still seems plenty long but good advice here is to limit how long of term users can give to SQLite so not to slow down your database. | ||
|
||
## Attached databases | ||
|
||
Max number of attached database: 10 databases | ||
|
||
We haven't done this, but what if you have two database files and want to query them like one database? SQLite lets you with ATTACH. This does make it hard to do things like have an IoT database per device and to address with ATTACH as it will only support 10. You're better off using some sort of data ingestion pipeline to something like BigQuery or Snowflake and then querying that. | ||
|
||
## Size of database / rows in a database | ||
|
||
- Size of a database: 281TB | ||
- Rows in a database: 1.8e+19 rows (theoretically) | ||
- Rows in a database: 2e+13 rows (effectively) | ||
|
||
In theory the database can grow to 281TB of data (which is effectively unlimited for all but the biggest problems in data.) Likewise with number of rows. The database systems can support 2^64 rows but in practice that isn't possible becauase with the smallest amount of data possible you'll run out of space around 2e+13 rows. Or, in other words, more than enough. | ||
|
||
To read through more of the limits, [check here][limits]. I just wanted to go through these with you to demonstrate that SQLite can scale its data capabilities as much as you can. It is powerful enough to tackle just about any problem. | ||
|
||
[limits]: https://www.sqlite.org/limits.html | ||
[s3]: https://aws.amazon.com/s3/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
Views are not unique to SQLite but SQLite certainly has its own version of them. | ||
|
||
The idea of a view is that it is an abstract or virtual table that makes use of other data in the table. A really good use case for us is that getting a list of track names with artists and albums requires two joins right now. Any time we want to get that information, we have two to write a query with two joins. | ||
|
||
```sql | ||
SELECT | ||
t.TrackId as id, | ||
ar.Name as artist, | ||
al.Title as album, | ||
t.Name as track | ||
FROM | ||
Track t | ||
|
||
JOIN | ||
Album al | ||
ON | ||
t.AlbumId = al.AlbumId | ||
|
||
JOIN | ||
Artist ar | ||
ON | ||
ar.ArtistId = al.ArtistId | ||
|
||
LIMIT 5; | ||
``` | ||
|
||
This is a super usable set of data for us to list out all the tracks in a database. Now if it only wasn't so burdensome to query. Well, spoilers, it doesn't have to be. We can make a view that automatically does this for us and presents it as a pretty table. | ||
|
||
```sql | ||
CREATE VIEW | ||
easy_tracks | ||
AS | ||
|
||
SELECT | ||
t.TrackId as id, | ||
ar.Name as artist, | ||
al.Title as album, | ||
t.Name as track | ||
FROM | ||
Track t | ||
|
||
JOIN | ||
Album al | ||
ON | ||
t.AlbumId = al.AlbumId | ||
|
||
JOIN | ||
Artist ar | ||
ON | ||
ar.ArtistId = al.ArtistId; | ||
``` | ||
|
||
Now go ahead and `SELECT * FROM easy_tracks LIMIT 15;` to see what we did. Cool, right? We can even start doing things like joins to this table as well. If you find yourself constantly doing the same joins (like we have this whole course) views can your friend. | ||
|
||
> SQLite does not materialized views like Postgres. That is to say, we cannot tell SQLite "run this query and store the results" like you can in Postgres. SQLite is always querying the live data underneath. | ||
> | ||
> SQLite also does not support inserting into views like other databases do. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"title": "What is Unique to SQLite", | ||
"icon": "fingerprint" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--- | ||
title: "SQLite Extensions" | ||
--- | ||
|
||
SQLite intentionally maintains a tight set of features and ruthlessly cuts out anything that doesn't contribute to that core use case of a small SQL database. But that said, SQLite has a rich ecosystem of extensions to fill in those gaps of other functionality you may want and many of those are written by the developers of SQLite themselves. | ||
|
||
[Click here to see the unofficial SQLite package manager, sqlpkg][sqlpkg]. | ||
|
||
As of writing there are 102 extensions in here that have been indexed, and more than that exist. If there's some core database thing you want to do that SQLite doesn't currently do, there likely exists and extension for it. | ||
|
||
If you're curious how they're written, Alex Garcia (who has written many SQLite extensions, including the vector search we're about to use) wrote one called [hello][hello] that is the minimum viable extension. | ||
|
||
So how do we load an extension? Let's load the hello extension. I'm going to use sqlpkg CLI but you can also do it manually. If you're following along with me [here are the instructions][install]. | ||
|
||
Once installed, do: | ||
|
||
```bash | ||
sqlpkg install asg017/hello | ||
sqlpkg which asg017/hello # copy the path this gives you | ||
``` | ||
|
||
Now that you've done that, load into the SQLite CLI and run | ||
|
||
```sql | ||
.load /Users/my-user/.sqlpkg/asg017/hello/hello0.dylib | ||
SELECT hello('Brian'); | ||
``` | ||
|
||
That's it! You use the .load syntax to load an extension and then you can start using it right away. Keep in mind you need to load the extension every time you open the file because, again, it's not a server, it's a library that's writing to a file. | ||
|
||
> hello() is just a function that was added by the extension. SQLite let's you query from these. Try `SELECT max(1,2,3,4,5,100);`. max() is built into SQLite | ||
[sqlpkg]: https://sqlpkg.org/ | ||
[hello]: https://github.com/asg017/sqlite-hello | ||
[cli]: https://github.com/nalgeon/sqlpkg-cli | ||
[install]: https://github.com/nalgeon/sqlpkg-cli?tab=readme-ov-file#download-and-install-preferred-method |
Empty file.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters