计算sqlite数据库中的行数

时间:2011-11-24 11:23:54

标签: linux performance sqlite

我在运行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);

3 个答案:

答案 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个可能不会导致表/索引扫描的表行计数解决方法(有警告):

  1. 注意对于可以使用INTEGER PRIMARY KEY AUTOINCREMENT作为主键的表,可以从sqlite_sequence sqlite元表中获取计数:

    从sqlite_sequence选择名称,seq

  2. seq将包含最后一个id或下一个id(我认为是最后一个但不确定)。

    1. &#34;从表格#34;中选择max(pkid),这可能会进行索引搜索而不是扫描(对于没有删除的表格也是如此)。
    2. 知道这一点,如果您的用例包含可以使用AUTOINCREMENT的表的UNIQUE删除,您可以对基于触发器的解决方案进行混合,并且只计算已删除的行(这可能比对大多数计算插入的计数更少。场景)。但是,如果您插入和删除相同的行两次,这也不会起作用。