优化所有记录的 SQLite 读取
optimize SQLite read of all records
问题总结
我可以非常快速地从单列 table 的单列中读取所有值。如何从 table 的单列中同样快速地读取所有值,该列也有其他几列?
详情
我正在使用 C++ api 读取包含单个 table 和 220 万条记录的 sqlite 数据库。
数据有一个 "coordinates" 列和(可选)其他几个列。 "coordinates" 列是一个 BLOB,目前总是 8 个字节长。其他列是 TEXT 和 REAL 的混合,TEXT 字符串从几个字符到大约 100 个字符(长度因记录而异)。
在一个实验中,我创建了带有 "coordinates" 列的 table 以及大约 15 个其他列。数据库文件总大小为 745 MB。我做了一个简单的
int rc = sqlite3_exec( db, "select coordinates from facilities", ReadSQLiteCallback, NULL, &errorMessage );
执行时间为 91 秒。
然后我创建了 table,只有 "coordinates" 列,没有其他数据列。数据库文件总大小为 36 MB。我 运行 同样的 select 语句,它花了 1.23 秒。
我试图了解是什么导致了速度上的这种巨大差异,以及当 table 具有这些额外的数据列时我如何提高速度。
我明白文件越大意味着需要阅读的数据越多。但我预计减速在最坏的情况下或多或少与文件大小呈线性关系(即,它可能需要 1.23 秒的 20 倍,或大约 25 秒,但不是 91 秒)。
问题第一部分
我没有在文件上使用索引,因为通常我倾向于像上面简单的 select 一样一次阅读整个 "coordinates" 列的大部分或全部内容。所以我真的不需要索引来排序或快速访问记录的子集。但是也许拥有一个索引可以帮助引擎在读取所有数据时更快地从一个可变大小的记录移动到下一个?
还有其他简单的想法可以帮助减少这 91 秒吗?
问题第二部分
假设没有灵丹妙药可以在单个 table 中将 91 秒(当包含其他 15 个数据列时)缩短到接近 1.23 秒(当仅存在坐标列时),似乎我可以使用多个 table,将坐标放在一个 table 中,将其余字段(我不需要这么快速访问)放在另一个中。
这听起来像是外键的用途,但似乎我的情况并不一定需要外键的复杂性,因为我在坐标之间有简单的一一对应关系table 和其他数据 table -- 坐标的每一行 table 对应其他数据 table 的相同行号,所以它真的就像我 "split" 每条记录跨越两个 tables.
所以问题是:我当然可以自己管理这种拆分,方法是为我的每条记录在两个 table 中添加一行,并从两个 table 中删除一行删除记录。但是有没有办法让 SQLite 为我管理这种拆分(我用谷歌搜索 "sqlite split record across tables" 但没有找到多少)?
索引通常用于搜索和排序。
但是,如果查询中实际使用的所有列都是单个索引的一部分,则您有一个 covering index,并且可以在不访问实际 table.
的情况下执行查询
coordinates
列上的索引可能会加速此查询。
即使有1:1关系,你仍然需要知道哪些行是关联的,所以你仍然需要一个table中的外键。 (这也恰好是主键,所以实际上你只是在两个 table 中复制了主键列。)
如果您没有 INTEGER PRIMARY KEY,您可以使用 internal ROWID 而不是您的主键。
问题总结
我可以非常快速地从单列 table 的单列中读取所有值。如何从 table 的单列中同样快速地读取所有值,该列也有其他几列?
详情
我正在使用 C++ api 读取包含单个 table 和 220 万条记录的 sqlite 数据库。
数据有一个 "coordinates" 列和(可选)其他几个列。 "coordinates" 列是一个 BLOB,目前总是 8 个字节长。其他列是 TEXT 和 REAL 的混合,TEXT 字符串从几个字符到大约 100 个字符(长度因记录而异)。
在一个实验中,我创建了带有 "coordinates" 列的 table 以及大约 15 个其他列。数据库文件总大小为 745 MB。我做了一个简单的
int rc = sqlite3_exec( db, "select coordinates from facilities", ReadSQLiteCallback, NULL, &errorMessage );
执行时间为 91 秒。
然后我创建了 table,只有 "coordinates" 列,没有其他数据列。数据库文件总大小为 36 MB。我 运行 同样的 select 语句,它花了 1.23 秒。
我试图了解是什么导致了速度上的这种巨大差异,以及当 table 具有这些额外的数据列时我如何提高速度。
我明白文件越大意味着需要阅读的数据越多。但我预计减速在最坏的情况下或多或少与文件大小呈线性关系(即,它可能需要 1.23 秒的 20 倍,或大约 25 秒,但不是 91 秒)。
问题第一部分
我没有在文件上使用索引,因为通常我倾向于像上面简单的 select 一样一次阅读整个 "coordinates" 列的大部分或全部内容。所以我真的不需要索引来排序或快速访问记录的子集。但是也许拥有一个索引可以帮助引擎在读取所有数据时更快地从一个可变大小的记录移动到下一个?
还有其他简单的想法可以帮助减少这 91 秒吗?
问题第二部分
假设没有灵丹妙药可以在单个 table 中将 91 秒(当包含其他 15 个数据列时)缩短到接近 1.23 秒(当仅存在坐标列时),似乎我可以使用多个 table,将坐标放在一个 table 中,将其余字段(我不需要这么快速访问)放在另一个中。
这听起来像是外键的用途,但似乎我的情况并不一定需要外键的复杂性,因为我在坐标之间有简单的一一对应关系table 和其他数据 table -- 坐标的每一行 table 对应其他数据 table 的相同行号,所以它真的就像我 "split" 每条记录跨越两个 tables.
所以问题是:我当然可以自己管理这种拆分,方法是为我的每条记录在两个 table 中添加一行,并从两个 table 中删除一行删除记录。但是有没有办法让 SQLite 为我管理这种拆分(我用谷歌搜索 "sqlite split record across tables" 但没有找到多少)?
索引通常用于搜索和排序。 但是,如果查询中实际使用的所有列都是单个索引的一部分,则您有一个 covering index,并且可以在不访问实际 table.
的情况下执行查询coordinates
列上的索引可能会加速此查询。即使有1:1关系,你仍然需要知道哪些行是关联的,所以你仍然需要一个table中的外键。 (这也恰好是主键,所以实际上你只是在两个 table 中复制了主键列。)
如果您没有 INTEGER PRIMARY KEY,您可以使用 internal ROWID 而不是您的主键。