我正在考虑将 SQLite 数据库用于处理大量数据系列的 C# 应用程序。数据目前位于多个 CSV 文件中,每个文件的大小最大为 20GB,格式如下:
2019.07.31 00:00:03.855,1.11568,1.11571,3,0
在迁移到 SQLite 时,我希望大大减小大小,但由于某种原因,我得到了一些不同的结果。
CSV 格式的示例字符串占用 44 个字节(43 个字符 + 新行)。据我了解的 SQLite 类型定义在 sqlite.org 中数据库中应该大致相同:23 字节日期时间文本 + 8*2 实数 + 1*2 整数 = 41 字节
dateTime 可以存储为 8 字节整数 (c# DateTime.Ticks),这应该将大小减少到每行约 26 个字节,几乎比 CSV 格式少两倍。
对于一个实验,我尝试导入 142,157 行数据。CSV 文件大小约为 6kk 字节,但生成的 DB 文件约为 5kk,几乎相同。压缩(在 DB Browser for SQLite 中可用)不会改变任何东西。
表架构是:
CREATE TABLE "Data" ( "dateTime" INTEGER, "value1" REAL, "value2" REAL, "value3" INTEGER, "value4" INTEGER )
示例行如下所示:
637001280038550000 1.11568 1.11571 3 0
是 SQLite 内部结构造成了如此大的开销吗?我怎样才能减小尺寸?
作为旁注,在 dateTime 字段上设置 Primary Key 会将示例数据文件的大小减少 0.3kk 字节,但添加唯一约束会增加 3kk 字节,使其总共约 8kk,这比 CSV 大得多。
更新
output from sqlite3_analyzer
w/t PK and contraints
Size of the file in bytes......................... 5242880
Bytes of user payload stored...................... 4349676 83.0%
Bytes of payload.................................. 4349852 83.0%
Bytes of metadata................................. 858115 16.4%
with PK
Size of the file in bytes......................... 4976640
Bytes of user payload stored...................... 3212420 64.5%
Bytes of payload.................................. 3212622 64.6%
Bytes of metadata................................. 1733838 34.8%
with PK and Unique constraint
Size of the file in bytes......................... 8134656
Bytes of user payload stored...................... 3212420 39.5%
Bytes of payload.................................. 3212622 64.6%
Bytes of metadata................................. 1733838 34.8%
*** Page counts for all tables and indices separately
TABLE............................................. 1214 61.1%
SQLITE_AUTOINDEX_TABLE_1.......................... 771 38.8%
Run Code Online (Sandbox Code Playgroud)
所以结果是内部结构占了 16%,PK 占了额外的 19%,但仍然减少了总大小,而独特的约束占了近 40%!
这个问题仍然有效。是否可以缩小数据库的大小,或者只能从中获得?
有一些方法。这里有两个似乎适合您的情况:
ROWID 是 SQLite 表默认具有的内部主键,每条记录占用 64 位。由于您正在讨论 datetime 列的 UNIQUE 约束,因此该列似乎是主键的一个很好的候选者(它总是附加一个唯一约束)。所以你可以创建一个没有 ROWID 的 SQLite 表,如下所示:
CREATE TABLE "Data" (
"dateTime" INTEGER PRIMARY KEY,
"value1" REAL,
"value2" REAL,
"value3" INTEGER,
"value4" INTEGER
) WITHOUT ROWID;
Run Code Online (Sandbox Code Playgroud)
实际上,我从未在 SQLite 中尝试过这种方法,但是:通过仅存储与前一行的差异,可以更紧凑地存储某些数据。在这种情况下,如果日期时间值可以按顺序存储到数据库中,那么日期时间值非常适合。在这种情况下,您将使用三列:
SQLite 将整数值单独存储为 2-9 个字节(包括一个存储模式字节),具体取决于它们的值。假设顺序主键平均为 4 个字节,增量值平均为 2.5 个字节,与当前的 9 字节整数相比,将节省 2.5 个字节。如果您的表中有多个可从增量存储中获益的列,则节省会更大,因为您只需要一次顺序主键。例如,如果value1……value4是随着时间的推移趋于增长和缩小的测量值,它们也是很好的候选者。
在主键值加载一行后n,您还必须检索主键值n DIV 1000(意味着整数除法)的行以获得增量值的基础。