{"id":19293664,"url":"https://github.com/tursodatabase/example-billing-tips","last_synced_at":"2025-04-22T07:32:22.464Z","repository":{"id":187708178,"uuid":"677422146","full_name":"tursodatabase/example-billing-tips","owner":"tursodatabase","description":"Tips and tricks for maximizing your Turso usage allowances using SQLite indexes and triggers.","archived":false,"fork":false,"pushed_at":"2023-08-23T16:34:11.000Z","size":16,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-01T20:51:23.112Z","etag":null,"topics":["sql","sqlite","turso"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tursodatabase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-11T14:32:22.000Z","updated_at":"2025-02-22T17:59:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"b10277ea-97e1-4d57-af6c-a654702df89b","html_url":"https://github.com/tursodatabase/example-billing-tips","commit_stats":null,"previous_names":["turso-extended/example-billing-tips","tursodatabase/example-billing-tips"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tursodatabase%2Fexample-billing-tips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tursodatabase%2Fexample-billing-tips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tursodatabase%2Fexample-billing-tips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tursodatabase%2Fexample-billing-tips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tursodatabase","download_url":"https://codeload.github.com/tursodatabase/example-billing-tips/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250195054,"owners_count":21390230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["sql","sqlite","turso"],"created_at":"2024-11-09T22:35:42.926Z","updated_at":"2025-04-22T07:32:22.224Z","avatar_url":"https://github.com/tursodatabase.png","language":"TypeScript","readme":"# Techniques to optimize your Turso billing allowance\n\nThis repository contains some examples for reducing the [billed usage] of a\n[Turso] database (in terms of rows read) for certain types queries that might\nnormally require an expensive full table scan. The techniques here also improve\nthe overall performance of the query as performed by the underlying SQLite query\nengine.\n\nRead the [companion blog post] that discusses the reasoning behind these\noptimizations.\n\nThe examples here boil down to two strategies:\n\n- [Use an index] on fields used with filtering, ordering, `min`, or `max`\n- Use [SQLite triggers] to pre-compute aggregate values, such as `sum` and `avg`\n\nThe SQL scripts here are designed to be fed directly into the [Turso CLI] or\n[sqlite3 CLI] for execution. For example, to create the example table and it\nstarting data:\n\n```sh\nturso db shell $DBNAME \u003c 01_table_and_data.sql\n```\n\n## SQL scripts in this repo\n\n### Initial table and data\n\nSQL: [01_table_and_data.sql]\n\nAll of the examples here assume the same starting point: a table and 4 rows.\nThis table is very simplistic and naive, but offers a starting point to\nunderstand the benefits of the optimizations below.\n\n### Use an index to optimize a filter (where clause with equality)\n\nSQL: [02_index_for_filter.sql]\n\nA query with a filter causes a full table scan. Add an index on the columns used\nfor filtering to reduce the number of reads to only the number of rows returned\nby the query.\n\n### Use an index to optimize `min`, `max`, and `order` with `limit`\n\nSQL: [03_index_for_min_max_order_limit.sql]\n\nA query that requires an ordering of data on a column causes a full table scan.\nAdd an index on that column to reduce the number of reads to only the number of\nrow values used by the query. For example, the `min()` function requires\nscanning each and every row in the table to find the lowest value, but an index\nallows SQLite to find the minimum value with a single row read.\n\n### Use triggers to maintain a table row count\n\nSQL: [04_triggers_for_table_row_count.sql]\n\nA query using `count()` causes a full table scan. Use triggers to maintain a\nrunning count of rows in another table when a row is inserted or deleted from\nthe original table. The other table can then be queried for the count, requiring\nonly a single row read.\n\n### Use triggers to maintain filtered table row counts per unique value\n\nSQL: [05_triggers_for_filtered_row_count.sql]\n\nSimilar to above, a filtered query using `count()` causes a full table scan.\nEven with an index on the column used in the filter, a scan of the matching rows\nis still required to compute a count. Use triggers to maintain running unique\nvalue counts in another table whenever a rows is inserted, updated or deleted\nfrom the original table. The other table can then be queried for the filtered\ncount, requiring only a single row read.\n\n### Use triggers to maintain an aggregate (`avg`) of all column values\n\nSQL: [06_triggers_for_column_avg.sql]\n\nA query using `avg()` causes a full table scan. Use triggers to maintain a\nrunning average in another table of the values in a column when a row value is\ninserted, updated, or deleted from the original table. The other table can then\nbe queried for the average, requiring only a single row read.\n\n## Code to monitor usage\n\nThe nodejs program under [monitor-usage] was useful for actively monitoring the\nactual usage of the test database as SQL commands were executed against it.\n\n\n[billed usage]: https://docs.turso.tech/billing-details\n[companion blog post]: https://blog.turso.tech/tips-for-maximizing-your-turso-billing-allowances-48a0fca163e9\n[Turso]: https://turso.tech\n[Use an index]: https://www.sqlite.org/queryplanner.html\n[SQLite triggers]: https://www.sqlite.org/lang_createtrigger.html\n[Turso CLI]: https://docs.turso.tech/reference/turso-cli\n[sqlite3 CLI]: https://www.sqlite.org/cli.html\n[01_table_and_data.sql]: 01_table_and_data.sql\n[02_index_for_filter.sql]: 02_index_for_filter.sql\n[03_index_for_min_max_order_limit.sql]: 03_index_for_min_max_order_limit.sql\n[04_triggers_for_table_row_count.sql]: 04_triggers_for_table_row_count.sql\n[05_triggers_for_filtered_row_count.sql]: 05_triggers_for_filtered_row_count.sql\n[06_triggers_for_column_avg.sql]: 06_triggers_for_column_avg.sql\n[monitor-usage]: monitor-usage\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftursodatabase%2Fexample-billing-tips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftursodatabase%2Fexample-billing-tips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftursodatabase%2Fexample-billing-tips/lists"}