【问题标题】:SQLite database size: more rows vs. more columnsSQLite 数据库大小:更多行与更多列
【发布时间】:2019-07-25 13:30:32
【问题描述】:

初步情况

假设我有一个如下所示的简单表格:

CREATE TABLE AppData (
    id                      INTEGER PRIMARY KEY,
    elementId               VARCHAR(36),
    timestampMs             INTEGER,
    enterTypeA              SMALLINT,
    exitTypeA               SMALLINT,
    enterTypeB              SMALLINT,
    exitTypeB               SMALLINT
);

CREATE UNIQUE INDEX app_data_index ON AppData (timestampMs DESC, elementId);

增加了索引,因为很多查询都是基于timestampMselementId来选择实体的。 我存储每分钟退出并为不同的elements 输入不同的types 值。例如:

elementId, timestampMs, enterTypeA, exitTypeA, enterTypeB, exitTypeB

1, 1559383200000, 4, 3, 1, 5  
2, 1559383200000, 8, 2, 3, 7  
1, 1559383260000, 2, 2, 4, 0  
2, 1559383260000, 1, 0, 9, 2  

问题描述

新的types 需要添加到数据库中。未来可能还会添加更多types。所以我尝试了两种不同的方法:

方法 1:
为新的types 添加更多列:

CREATE TABLE AppData (
    id                      INTEGER PRIMARY KEY,
    elementId               VARCHAR(36),
    timestampMs             INTEGER,
    enterTypeA              SMALLINT,
    exitTypeA               SMALLINT,
    enterTypeB              SMALLINT,
    exitTypeB               SMALLINT,
    enterTypeC              SMALLINT,
    exitTypeC               SMALLINT
);

CREATE UNIQUE INDEX app_data_index ON AppData (timestampMs DESC, elementId);

方法 2:
每个type 都有一个新行(意味着更大的索引):

CREATE TABLE AppData (
    id                      INTEGER PRIMARY KEY,
    elementId               VARCHAR(36),
    timestampMs             INTEGER,
    enterValue              SMALLINT,
    exitValue               SMALLINT,
    type                    SMALLINT
);

CREATE UNIQUE INDEX app_data_index ON AppData (timestampMs DESC, elementId, type);

我个人更喜欢方法 2,因为它减少了重复。

我用 5 个elements 和 3 个types 测试了这两种方法并插入了 10 天的测试数据。结果表明,方法 1 的数据库大小远小于方法 2 的大小(从我的角度来看,这是合理的逻辑,因为方法 2 的行数增加了三倍):

方法 1: 8.2 MB | 144'000 个条目
方法 2: 24.6 MB | 432'000 个条目

问题

正如我所见,两种解决方案中的索引大小约为数据库大小的 50%,因此很明显方法 2 的数据库大小总是会更大。

SQLite 中的更多行而不是更多列总是会对数据库大小产生如此大的影响吗?

到目前为止,我还没有找到进一步减小方法 2 大小的解决方案。也许这是由于索引而无法实现的?

【问题讨论】:

  • 您也许可以删除id 列,并使用您当前的唯一索引将其设为WITHOUT ROWID 表作为新的主键。这将大大减少大小(并在给定 pk 列的情况下加快非 pk 列的查找速度)
  • 感谢您的提示。我以前不知道WITHOUT ROWID。所以我测试了它,没有索引和新的主键。它将第二种方法的数据库大小减少了大约 12 MB。

标签: sqlite


【解决方案1】:

这两个版本中哪个会占用更多空间的问题并不像适合您需要的数据库结构那么重要。第二个版本更可取,原因如下:

  • 如果您需要将表限制为仅某些类型,一个简单的WHERE 子句就足够了。在第一个版本中,您基本上总是在查询时返回 every 类型
  • 在第二个版本中可以进行聚合。您可以轻松地按类型聚合所有时间戳。这在第一个版本中要困难得多。
  • 如果您需要将第二个版本中的任何列链接到其他表,这相当简单。另一方面,在第一个版本中,您可能需要链接每个单独的进入/退出列。

关于存储,在两种方案中存储相同数量的数据应该非常相似,肯定在一个数量级之内,并且可能在 2 倍之内。设计问题似乎是更大的问题。

【讨论】:

  • 我同意你的观点,从方案来看,第二种方法更可取,作为开发人员,我也更喜欢第二种方法。但是我在只有有限存储可用的嵌入式环境中使用 SQLite。所以这可能是更好的架构和数据库大小之间的折衷。
  • 我想这取决于你有多少空间(例如在你的 Android 手机上),以及这有多重要。
  • 不是很多 ;) 数据库是否大于因子 3 至关重要。
  • 最后我采用了第二种方法,删除了 PK id 列,使用WITHOUT ROWID,删除索引并按照@Shawn 的建议在以前的唯一索引列上设置 PK。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 2011-11-29
相关资源
最近更新 更多