mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-27 20:34:12 +02:00
db.analyze() and table.analyze() methods, refs #366
This commit is contained in:
parent
b6dad08a83
commit
541f64ddb0
3 changed files with 83 additions and 0 deletions
|
|
@ -2204,6 +2204,33 @@ You can create a unique index by passing ``unique=True``:
|
||||||
|
|
||||||
Use ``if_not_exists=True`` to do nothing if an index with that name already exists.
|
Use ``if_not_exists=True`` to do nothing if an index with that name already exists.
|
||||||
|
|
||||||
|
.. _python_api_analyze:
|
||||||
|
|
||||||
|
Optimizing index usage with ANALYZE
|
||||||
|
===================================
|
||||||
|
|
||||||
|
The `SQLite ANALYZE command <https://www.sqlite.org/lang_analyze.html>`__ can be used to build a table of statistics which the query planner can then use to make better decisions about which indexes to use for a given query.
|
||||||
|
|
||||||
|
You should run ``ANALYZE`` if your database is large and you do not think your indexes are being efficiently used.
|
||||||
|
|
||||||
|
To run ``ANALYZE`` against every index in a database, use this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
db.analyze()
|
||||||
|
|
||||||
|
To run it just against a specific named index, pass the name of the index to that method:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
db.analyze("idx_countries_country_name")
|
||||||
|
|
||||||
|
To run against all indexes attached to a specific table, you can either pass the table name to ``db.analyze(...)`` or you can call the method directly on the table, like this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
db["dogs"].analyze()
|
||||||
|
|
||||||
.. _python_api_vacuum:
|
.. _python_api_vacuum:
|
||||||
|
|
||||||
Vacuum
|
Vacuum
|
||||||
|
|
|
||||||
|
|
@ -923,6 +923,13 @@ class Database:
|
||||||
"Run a SQLite ``VACUUM`` against the database."
|
"Run a SQLite ``VACUUM`` against the database."
|
||||||
self.execute("VACUUM;")
|
self.execute("VACUUM;")
|
||||||
|
|
||||||
|
def analyze(self, name=None):
|
||||||
|
"Run ``ANALYZE`` against the entire database or a named table or index."
|
||||||
|
sql = "ANALYZE"
|
||||||
|
if name is not None:
|
||||||
|
sql += " [{}]".format(name)
|
||||||
|
self.execute(sql)
|
||||||
|
|
||||||
|
|
||||||
class Queryable:
|
class Queryable:
|
||||||
def exists(self) -> bool:
|
def exists(self) -> bool:
|
||||||
|
|
@ -2902,6 +2909,10 @@ class Table(Queryable):
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def analyze(self):
|
||||||
|
"Run ANALYZE against this table"
|
||||||
|
self.db.analyze(self.name)
|
||||||
|
|
||||||
def analyze_column(
|
def analyze_column(
|
||||||
self, column: str, common_limit: int = 10, value_truncate=None, total_rows=None
|
self, column: str, common_limit: int = 10, value_truncate=None, total_rows=None
|
||||||
) -> "ColumnDetails":
|
) -> "ColumnDetails":
|
||||||
|
|
|
||||||
45
tests/test_analyze.py
Normal file
45
tests/test_analyze.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def db(fresh_db):
|
||||||
|
fresh_db["one_index"].insert({"id": 1, "name": "Cleo"}, pk="id")
|
||||||
|
fresh_db["one_index"].create_index(["name"])
|
||||||
|
fresh_db["two_indexes"].insert({"id": 1, "name": "Cleo", "species": "dog"}, pk="id")
|
||||||
|
fresh_db["two_indexes"].create_index(["name"])
|
||||||
|
fresh_db["two_indexes"].create_index(["species"])
|
||||||
|
return fresh_db
|
||||||
|
|
||||||
|
|
||||||
|
def test_analyze_whole_database(db):
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes"}
|
||||||
|
db.analyze()
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes", "sqlite_stat1"}
|
||||||
|
assert list(db["sqlite_stat1"].rows) == [
|
||||||
|
{"tbl": "two_indexes", "idx": "idx_two_indexes_species", "stat": "1 1"},
|
||||||
|
{"tbl": "two_indexes", "idx": "idx_two_indexes_name", "stat": "1 1"},
|
||||||
|
{"tbl": "one_index", "idx": "idx_one_index_name", "stat": "1 1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("method", ("db_method_with_name", "table_method"))
|
||||||
|
def test_analyze_one_table(db, method):
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes"}
|
||||||
|
if method == "db_method_with_name":
|
||||||
|
db.analyze("one_index")
|
||||||
|
elif method == "table_method":
|
||||||
|
db["one_index"].analyze()
|
||||||
|
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes", "sqlite_stat1"}
|
||||||
|
assert list(db["sqlite_stat1"].rows) == [
|
||||||
|
{"tbl": "one_index", "idx": "idx_one_index_name", "stat": "1 1"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_analyze_index_by_name(db):
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes"}
|
||||||
|
db.analyze("idx_two_indexes_species")
|
||||||
|
assert set(db.table_names()) == {"one_index", "two_indexes", "sqlite_stat1"}
|
||||||
|
assert list(db["sqlite_stat1"].rows) == [
|
||||||
|
{"tbl": "two_indexes", "idx": "idx_two_indexes_species", "stat": "1 1"},
|
||||||
|
]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue