Skip to content

Commit 657f7d4

Browse files
committed
set WITHOUT ROWID for the 2 binding tables
less db size especially when with lots of chunks, 82M -> 77M for f4c on 1.5GB data
1 parent a9343b6 commit 657f7d4

6 files changed

Lines changed: 22 additions & 2 deletions

File tree

prime_backup/db/migrations/migration_3_4.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from prime_backup.db.migrations import MigrationImplBase
1111
from prime_backup.db.values import BlobStorageMethod
12+
from prime_backup.utils import db_utils
1213

1314

1415
class _V4:
@@ -50,13 +51,15 @@ class _V4:
5051
Column('chunk_group_id', Integer, ForeignKey('chunk_group.id'), primary_key=True),
5152
Column('chunk_offset', BigInteger, primary_key=True),
5253
Column('chunk_id', Integer, ForeignKey('chunk.id'), index=True, nullable=False),
54+
**({'sqlite_with_rowid': False} if db_utils.check_sqlite_without_rowid() else {}),
5355
)
5456
BlobChunkGroupBinding = Table(
5557
'blob_chunk_group_binding',
5658
Base.metadata,
5759
Column('blob_id', Integer, ForeignKey('blob.id'), primary_key=True),
5860
Column('chunk_group_offset', BigInteger, primary_key=True),
5961
Column('chunk_group_id', Integer, ForeignKey('chunk_group.id'), index=True, nullable=False),
62+
**({'sqlite_with_rowid': False} if db_utils.check_sqlite_without_rowid() else {}),
6063
)
6164
File = Table(
6265
'file',

prime_backup/db/schema.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
55

66
from prime_backup.db.values import BackupTagDict
7+
from prime_backup.utils import db_utils
78

89

910
class Base(DeclarativeBase):
@@ -78,6 +79,7 @@ class ChunkGroupChunkBinding(Base):
7879
"""
7980

8081
__tablename__ = 'chunk_group_chunk_binding'
82+
__table_args__ = {'sqlite_with_rowid': False} if db_utils.check_sqlite_without_rowid() else {}
8183

8284
chunk_group_id: Mapped[int] = mapped_column(ForeignKey('chunk_group.id'), primary_key=True)
8385
chunk_offset: Mapped[int] = mapped_column(BigInteger, primary_key=True) # &chunk[0] - &chunk_group[0]
@@ -94,6 +96,7 @@ class BlobChunkGroupBinding(Base):
9496
"""
9597

9698
__tablename__ = 'blob_chunk_group_binding'
99+
__table_args__ = {'sqlite_with_rowid': False} if db_utils.check_sqlite_without_rowid() else {}
97100

98101
blob_id: Mapped[int] = mapped_column(ForeignKey('blob.id'), primary_key=True)
99102
chunk_group_offset: Mapped[int] = mapped_column(BigInteger, primary_key=True)

prime_backup/utils/db_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ def check_sqlite_row_number() -> bool:
2828
return sqlite3.sqlite_version_info >= (3, 25, 0)
2929

3030

31+
def check_sqlite_without_rowid() -> bool:
32+
"""
33+
https://sqlite.org/withoutrowid.html#compatibility
34+
"""
35+
return sqlite3.sqlite_version_info >= (3, 8, 2)
36+
37+
3138
def vacuum_into_via_backup_api(src_db_path: PathLike, into_path: PathLike):
3239
"""
3340
Fallback for VACUUM INTO on old SQLite versions that do not support "VACUUM INTO"
@@ -48,3 +55,4 @@ def vacuum_into_via_backup_api(src_db_path: PathLike, into_path: PathLike):
4855
print('json query:', check_sqlite_json_query_support())
4956
print('vacuum into:', check_sqlite_vacuum_into_support())
5057
print('row number:', check_sqlite_row_number())
58+
print('without rowid:', check_sqlite_without_rowid())

tests/data/schema_ddl_v4.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ tables:
3535
FOREIGN KEY(blob_id) REFERENCES blob (id),
3636
FOREIGN KEY(chunk_group_id) REFERENCES chunk_group (id)
3737
)
38+
WITHOUT ROWID
3839
chunk: |-
3940
CREATE TABLE chunk (
4041
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
@@ -62,6 +63,7 @@ tables:
6263
FOREIGN KEY(chunk_group_id) REFERENCES chunk_group (id),
6364
FOREIGN KEY(chunk_id) REFERENCES chunk (id)
6465
)
66+
WITHOUT ROWID
6567
db_meta: |-
6668
CREATE TABLE db_meta (
6769
magic INTEGER NOT NULL,

tests/schema_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def collect_schema(engine: Engine) -> SchemaDDL:
2525
with engine.connect() as conn:
2626
def collect(sql: str) -> Dict[str, str]:
2727
return {
28-
row.name: row.sql
28+
row.name: row.sql.strip()
2929
for row in conn.execute(text(sql))
3030
if not row.name.startswith(_SQLITE_INTERNAL_PREFIX)
3131
}

tests/test_schema_ddl.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
66
Review the diff of the updated YAML files and commit them as the new golden values
77
"""
8+
import re
89
import unittest
910
from pathlib import Path
1011

1112
from ruamel.yaml import YAML
1213

14+
from prime_backup.utils import db_utils
1315
from tests import schema_utils
1416

1517
__DATA_DIR = Path(__file__).parent / 'data'
@@ -22,7 +24,9 @@ def __load_expected(filename: str) -> schema_utils.SchemaDDL:
2224

2325

2426
def _assert_schema_matches(tc: unittest.TestCase, actual: schema_utils.SchemaDDL, filename: str, exact_match: bool):
25-
import re
27+
if not db_utils.check_sqlite_without_rowid():
28+
tc.fail(f'SQLite without rowid is not supported, version: {db_utils.get_sqlite_version()}')
29+
2630
frozen_answer = __load_expected(filename)
2731
hint = f'Re-run tests/tools/dump_schema_ddl.py to update {filename}.'
2832
if exact_match:

0 commit comments

Comments
 (0)