Usage & Billing
For the Starter and Scaler plans, Turso usage is limited monthly based on the following usage observations during each calendar month:
- Number of table rows read
- Number of table rows written
- Amount of total storage
In billing plans that include monthly quotas for row reads, row writes, and total storage, any query that exceeds these limits will result in a failure, indicated by the BLOCKED
error code.
Rows Read
In SQLite, the term “row read” actually refers to a “row scan” during statement execution. Key points to remember with the Turso CLI metrics:
- SQL Queries: May scan more rows than returned.
- SQL Updates: Each updated row results in at least one row scan.
Aggregate Function Impact
Using functions like count
, avg
, min
, max
, and sum
results in a row scan for every row considered in the aggregation.
Improve query efficiency by storing aggregate values in a separate table and updating it transactionally with the base table changes.
Full Table Scans
Queries lacking index support perform a full table scan, incurring a row scan for each table row.
Seek strategies to minimize costly table scans.
Complex Query Costs
Table joins, subqueries, and compound queries incur a row scan for each considered row from all involved tables.
Update Mechanics
SQL updates read (and write) each row they modify. Absent an index for row filtering, a full table scan is performed, adding a read for each table row, plus a write for each updated row.
ALTER TABLE
and Row Reads
ALTER TABLE
operations, especially those rewriting row contents, necessitate a full table scan, incurring a read for each table row. However, not all ALTER TABLE
actions, like DROP COLUMN
, lead to full scans. Be mindful of potential row writes as well.
Indexing Costs
Adding an index to an existing table triggers a full table scan, with one read per existing row.
SQLite System Tables
Internal SQLite tables, like dbstat
and those with sqlite_
prefix, don’t incur row reads in queries.
Zero-Read Commands
Commands not involving row reads/writes, like select 1
, default to one row read.
Rows Written
In SQLite, a “row written” encompasses both the insertion of a new row and the update of an existing row.
ALTER TABLE
and Row Writes
ALTER TABLE
operations can result in a row write for each existing row, especially if the row data is altered during the process. It’s important to understand how different types of ALTER TABLE
statements impact row writes.
Implications of Aborted Transactions
Even if a transaction is not committed, any row that was inserted or updated during the transaction incurs a row write. This underscores the importance of transaction management in controlling database writes.
ALTER TABLE
actions may also lead to row reads, adding another layer to consider when modifying table structures.
Total Storage
SQLite utilizes the virtual table dbstat
to calculate the total space used by all tables and indexes. The base unit for this measurement is a database file page, which is 4KB.
In SQLite, the VACUUM
command is a common tool for optimizing storage by compacting the database. However, it’s important to note that this command is currently disabled in Turso. Future updates may introduce options for developers to efficiently manage and reduce the total storage footprint of their databases.
Reducing Usage
Query Execution
Familiarizing yourself with the SQLite query planner can significantly enhance your understanding of how your queries are executed. This knowledge is pivotal in optimizing query efficiency.
Query Planning
Utilize the EXPLAIN QUERY PLAN
statement to gain insights into your query’s execution plan. This tool is invaluable for identifying whether your query is performing a full table scan and if it’s leveraging the most efficient index to reduce unnecessary reads.
Indexing
Ensure that your queries are designed to take advantage of indexes for row filtering. The absence of suitable indexes forces SQLite to resort to full table scans, incrementally increasing the read count by one for each row in the table. Efficient indexing is key to minimizing this overhead.
Incorporating necessary indexes at the table creation stage is a best practice. Adding indexes to tables that already contain rows triggers a full table scan, with each existing row necessitating one read. Proactive index management is crucial for maintaining optimal database performance.
Was this page helpful?