mirror of
https://github.com/simonw/datasette.git
synced 2026-10-22 17:27:01 +02:00
Merge spike/budget into spike/final
Conflicts: - database.py: keep both class attributes (is_scratch from scratch, immutable_count_time_limit_ms from budget). - cli.py check_databases(): take budget's catalog-first check and keep scratch's rule that scratch databases are never checked (they are skipped in _databases_needing_check()); the --crossdb warning no longer counts scratch databases, which are never ATTACHed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwkLo2rJWidpkDVT3HkvNv
This commit is contained in:
commit
c786d91cf9
20 changed files with 1934 additions and 259 deletions
|
|
@ -2220,6 +2220,8 @@ Datasette is designed to serve anything from one database to thousands of databa
|
|||
|
||||
**Schema changes** made by Datasette's own writes are detected as soon as the write finishes, and databases that other processes may change are polled - see :ref:`setting_schema_watch_interval_ms`. If a database file is replaced (for example by renaming a new file over it) or deleted, connections to the old file are discarded. Once Datasette has seen a database file exist it will not create it again: writes to a deleted file fail with an error rather than silently creating a new empty database. A database added with :ref:`datasette_add_database` whose file does not exist yet is created by its first write.
|
||||
|
||||
**Pages that cover many databases** - the index page, ``allowed_resources()`` listings and their derived-table permission rules, ``/-/api`` and the like - read what they need about each database's tables from the :ref:`catalog tables in the internal database <internals_internal>` instead of opening every database. Plugins that summarise many databases should do the same: a query against ``catalog_tables``, ``catalog_columns`` or ``catalog_foreign_keys`` costs the same however many databases are attached, while calling methods such as ``db.table_names()`` on every database opens a connection to each of them. Use the live methods on a single :ref:`Database <internals_database>` when you need the database's own current answer.
|
||||
|
||||
With :ref:`setting_num_sql_threads` set to ``0`` (for example in Pyodide) there are no threads: reads and writes run on the event loop, read connections are still pooled and closed when idle, and the write connection stays open until the database is closed.
|
||||
|
||||
Every new connection is set up by the :ref:`plugin_hook_prepare_connection` plugin hook, except isolated connections, the brief connections used to check a file's schema version, and connections to the internal database. Because connections are opened and closed as needed, anything set up on a connection - functions, temporary tables, ``ATTACH``, ``PRAGMA`` settings - only lasts as long as that connection, and is not seen by other connections to the same database. Use ``prepare_connection`` for anything every connection needs.
|
||||
|
|
@ -2980,7 +2982,7 @@ You can also set the ``DATASETTE_INTERNAL`` environment variable to specify this
|
|||
export DATASETTE_INTERNAL=/path/to/internal.db
|
||||
datasette mydatabase.db
|
||||
|
||||
Datasette maintains tables called ``catalog_databases``, ``catalog_tables``, ``catalog_views``, ``catalog_columns``, ``catalog_indexes``, ``catalog_foreign_keys`` with details of the attached databases and their schemas. These tables should not be considered a stable API - they may change between Datasette releases.
|
||||
Datasette maintains tables called ``catalog_databases``, ``catalog_tables``, ``catalog_views``, ``catalog_columns``, ``catalog_indexes``, ``catalog_foreign_keys`` with details of the attached databases and their schemas. ``catalog_tables.type`` is the type ``PRAGMA table_list`` reports for each table (``table``, ``virtual`` or ``shadow``), or ``NULL`` if unknown. These tables should not be considered a stable API - they may change between Datasette releases.
|
||||
|
||||
Metadata is stored in tables ``metadata_instance``, ``metadata_databases``, ``metadata_resources`` and ``metadata_columns``. Plugins can interact with these tables via the :ref:`get_*_metadata() and set_*_metadata() methods <datasette_get_set_metadata>`.
|
||||
|
||||
|
|
@ -3027,7 +3029,7 @@ The internal database schema is as follows:
|
|||
database_name TEXT,
|
||||
table_name TEXT,
|
||||
rootpage INTEGER,
|
||||
sql TEXT,
|
||||
sql TEXT, type TEXT,
|
||||
PRIMARY KEY (database_name, table_name),
|
||||
FOREIGN KEY (database_name) REFERENCES catalog_databases(database_name)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ Add ``/.json`` to the end of the URL for the JSON version of the underlying data
|
|||
|
||||
The index page can also be accessed at ``/-/``, useful for if the default index page has been replaced using an :ref:`index.html custom template <customization_custom_templates>`. The ``/-/`` page will always render the default Datasette ``index.html`` template.
|
||||
|
||||
.. _IndexView_row_counts:
|
||||
|
||||
The index page reads table names, columns, primary keys, hidden tables and foreign key relationships from the :ref:`internal database catalog <internals_internal>`, so it does not need to open each attached database. Row counts are the exception: they need a ``count(*)`` per table. The index page shows row counts when it lists at most 20 databases that would need counting, each smaller than 100MB, and the counts for a database are dropped if any of them takes longer than 10ms. With more databases than that it shows the number of tables in each database, sorts the most interesting tables first by their number of foreign key relationships, and only includes row counts that are already known without opening a database: counts for :ref:`immutable databases <performance_immutable_mode>` from ``--inspect-file`` or calculated by an earlier page. Visit a database's page for its row counts.
|
||||
|
||||
.. _DatabaseView:
|
||||
|
||||
Database
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ To open a file in immutable mode pass it to the datasette command using the ``-i
|
|||
|
||||
datasette -i data.db
|
||||
|
||||
When you open a file in immutable mode like this Datasette will also calculate and cache the row counts for each table in that database when it first starts up, further improving performance.
|
||||
When you open a file in immutable mode like this Datasette will also calculate and cache the row counts for each table in that database the first time a page needs them, further improving performance. (Earlier versions counted every immutable database at startup.)
|
||||
|
||||
.. _performance_inspect:
|
||||
|
||||
Using "datasette inspect"
|
||||
-------------------------
|
||||
|
||||
Counting the rows in a table can be a very expensive operation on larger databases. In immutable mode Datasette performs this count only once and caches the results, but this can still cause server startup time to increase by several seconds or more.
|
||||
Counting the rows in a table can be a very expensive operation on larger databases. In immutable mode Datasette performs this count only once and caches the results, but this can still make the first page that shows those counts take several seconds or more.
|
||||
|
||||
If you know that a database is never going to change you can precalculate the table row counts once and store then in a JSON file, then use that file when you later start the server.
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ To create a JSON file containing the calculated row counts for a database, use t
|
|||
|
||||
datasette inspect data.db --inspect-file=counts.json
|
||||
|
||||
Then later you can start Datasette against the ``counts.json`` file and use it to skip the row counting step and speed up server startup::
|
||||
Then later you can start Datasette against the ``counts.json`` file and use it to skip the row counting step entirely::
|
||||
|
||||
datasette -i data.db --inspect-file=counts.json
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue