我在运行Linux的ARM嵌入式平台上有一个sqlite数据库,资源有限。存储设备是microSD卡。 Sqlite版本是3.7.7.1。访问sqlite的应用程序是用C ++编写的。
我想以规则的间隔知道几个表中的行数。我目前使用
select count(*) from TABLENAME;
获取此信息。我遇到了性能问题:当表格大小达到某个点(~200K行)时,每次检查表格大小时都会有很多系统和iowait加载。
当我写这篇文章时,我虽然查找表中的行数会很快,因为它可能存储在某个地方。但是现在我怀疑sqlite实际上是查看所有行的,当我通过数据不适合磁盘缓存的点时,我得到了很多io加载。这大致适合数据库大小和可用内存。
有人能告诉我sqlite是否以我怀疑的方式行事?
有没有办法获得表行数而不会产生这样的负载量?
编辑:plaes询问了表格布局:
CREATE TABLE %s (timestamp INTEGER PRIMARY KEY, offset INTEGER, value NUMERIC);
答案 0 :(得分:2)
此表是否有integer
索引?如果没有,那么添加一个。否则它必须扫描整个表来计算项目。
这是SQLite代码中的注释的摘录,它实现了COUNT()
解析和执行:
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
** SELECT count(*) FROM <tbl>
**
** where the Table structure returned represents table <tbl>.
**
** This statement is so common that it is optimized specially. The
** OP_Count instruction is executed either on the intkey table that
** contains the data for table <tbl> or on one of its indexes. It
** is better to execute the op on an index, as indexes are almost
** always spread across less pages than their corresponding tables.
*/
[...]
/* Search for the index that has the least amount of columns. If
** there is such an index, and it has less columns than the table
** does, then we can assume that it consumes less space on disk and
** will therefore be cheaper to scan to determine the query result.
** In this case set iRoot to the root page number of the index b-tree
** and pKeyInfo to the KeyInfo structure required to navigate the
** index.
**
** (2011-04-15) Do not do a full scan of an unordered index.
此外,您可以使用EXPLAIN QUERY PLAN
get more information查询您的查询。
答案 1 :(得分:1)
根据我收集的所有信息,count()显然确实需要扫描表格。正如plaes指出的那样,如果在整数索引列上完成计数,则速度会更快,但仍需要扫描索引。
我现在所做的是将行计数存储在某处,并在我用来执行插入和删除的相同事务中手动递增/递减它以保持一致。
答案 2 :(得分:0)
以下是2个可能不会导致表/索引扫描的表行计数解决方法(有警告):
注意对于可以使用INTEGER PRIMARY KEY AUTOINCREMENT作为主键的表,可以从sqlite_sequence sqlite元表中获取计数:
从sqlite_sequence选择名称,seq
seq将包含最后一个id或下一个id(我认为是最后一个但不确定)。
知道这一点,如果您的用例包含可以使用AUTOINCREMENT的表的UNIQUE删除,您可以对基于触发器的解决方案进行混合,并且只计算已删除的行(这可能比对大多数计算插入的计数更少。场景)。但是,如果您插入和删除相同的行两次,这也不会起作用。