【问题标题】:iOS sqlite3_step hold / freeze after last row dataiOS sqlite3_step 在最后一行数据后保持/冻结
【发布时间】:2013-08-10 00:25:34
【问题描述】:

读取最后一行数据后,我的 sqlite3_step 保持 1 秒。为什么?

-(NSDictionary*)specificationItemsForConfigurationsIds:(NSString*)configurationsIdsStr
{
    [self databaseOpen];

    NSString *query = [NSString stringWithFormat:@"SELECT SpecItem.id,SpecItem.name,ConfigurationSpec.configuration_id\
                   FROM (SpecItem INNER JOIN ConfigurationSpec ON ConfigurationSpec.spec_item_id=SpecItem.id)\
                   WHERE (SpecItem.parent_id=12 OR SpecItem.parent_id=34 OR SpecItem.id=23 OR SpecItem.id=27) AND ConfigurationSpec.configuration_id IN (%@)",configurationsIdsStr];

sqlite3_stmt *statement;

NSMutableDictionary* configurationsWithSpecItems = [NSMutableDictionary new];

if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
    while (sqlite3_step(statement) == SQLITE_ROW)
    {
        int specItemId = sqlite3_column_int(statement, 0);
        NSString* specItemName = [self sqlite3_column_text_asString_ofStatement:statement
                                                                       atColumn:1];
        int configId = sqlite3_column_int(statement, 2);
        NSString* configIdNumber = [NSString stringWithFormat:@"%d",configId];

        NSMutableArray* specItems = [configurationsWithSpecItems objectForKey:configIdNumber];
        if(specItems == nil)
        {
            specItems = [NSMutableArray new];
            [configurationsWithSpecItems setObject:specItems
                                            forKey:configIdNumber];
        }

        SpecificationItem* specItem = [SpecificationItem specificationItemWithId:specItemId
                                                                            name:specItemName];

        [specItems addObject:specItem];
        // When we read last row data, getting from here to POINT 2 takes 1s
    }
    // POINT 2
    sqlite3_finalize(statement);
}
[self databaseClose];
return configurationsWithSpecItems;
}

单次读取一行需要 2-3ms,但在最后一个退出 while 循环后需要 1s,这对我来说太多了。

此查询的 EXPLAIN QUERY PLAN 输出:

0 0 1 SCAN TABLE Configuration (~100000 rows) 
0 0 0 EXECUTE LIST SUBQUERY 1
1 0 0 SEARCH TABLE Configuration USING AUTOMATIC COVERING INDEX (model_id=?) (~7 rows) 
0 1 0 SEARCH TABLE SpecItem USING INTEGER PRIMARY KEY (rowid=?) (~1 rows) 

【问题讨论】:

  • 请为您的查询显示EXPLAIN QUERY PLAN 的输出。
  • 0 0 1 扫描表配置(~100000 行)0 0 0 执行列表子查询 1 1 0 0 使用自动覆盖索引的搜索表配置(model_id=?)(~7 行)0 1 0 搜索TABLE SpecItem USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
  • 请将此信息添加到您的问题中。为什么表名是SpecItem 而不是Spec
  • 问题已编辑。请帮忙。
  • 你确定ConfigurationSpecmodel_id 来自哪里? configurationsIdStr?该子查询似乎很重要。

标签: ios iphone ipad sqlite


【解决方案1】:

延迟有两种解释;一个或两个都可能适用:

  • 所有匹配的记录都在Configuration 表的开头。在最后一条匹配的记录之后,SQLite 仍然要搜索所有剩余的记录,但没有匹配到。
  • SQLite 在model_id 列上创建一个临时索引,因为它估计没有它查询会更慢。查询完成后,必须再次删除该索引;您看到的是在(自动)事务结束时同步所需的时间。

model_id 列上创建索引将有助于避免这两点。

如果可能,您应该尝试将子查询(configurationsIdStr)合并到外部查询中;而不是:

... ConfigurationSpec.configuration_id IN (
           SELECT configuration_id FROM Configuration WHERE model_id = 42)

使用这样的东西:

... ConfigurationSpec.model_id = 42

避免这种间接性使得 SQLite 更容易优化查询执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多