iPhone SQLite(FMDB)查询需要花费过多时间

时间:2013-01-04 13:31:35

标签: iphone sqlite query-optimization fmdb


我正在尝试执行其中包含 group by 子句的查询。
查询执行时间为0.012243秒 但是,当我执行 [resultset next] 时,第一次调用时需要5秒以上。

实施例

NSMutableArray *recordsArray = [[NSMutableArray alloc] init];

NSString * query = @"select count(id), SUBSTR(purchase_date, 0,11) as purchase_date from sales where purchase_date LIKE '2012-12%' group by purchase_date order by purchase_date asc";

NSDate * date1 = [NSDate date];

FMResultSet * resultset = [database executeQuery:query];

NSDate * date2 = [NSDate date];
NSTimeInterval timeTaken = [date2 timeIntervalSinceDate:date1];
NSLog(@"TimeTaken: %f", timeTaken);     //outputs around 0.012


while ([resultset next])
{
    [recordsArray addObject:[resultset resultDictionary]];
}

date2 = [NSDate date];      
timeTaken = [date2 timeIntervalSinceDate:date1];
NSLog(@"TimeTaken 2: %f", timeTaken);   //outputs around 5.5 seconds

我还能够确定所有花费的时间是第一次调用 [resultset next]

我还尝试通过生成 UNION 'ed查询来修改查询以删除 group by 子句,如

NSString * query2 = @"select * from 
(
    select count(id), SUBSTR(purchase_date, 0,11) as purchase_date from sales where purchase_date = 2012-12-01
    UNION
    select count(id), SUBSTR(purchase_date, 0,11) as purchase_date from sales where purchase_date = 2012-12-02
    UNION
    select count(id), SUBSTR(purchase_date, 0,11) as purchase_date from sales where purchase_date = 2012-12-03
    ....
    UNION
    select count(id), SUBSTR(purchase_date, 0,11) as purchase_date from sales where purchase_date = 2012-12-31
) where purcase_date is not NULL order by purchase_date asc";

执行此查询也需要0.2秒,但第一次调用[结果集下一步]并且时间开始时间为7秒。

其他信息
该表目前有8000多行,但对于我的一些用户来说,这个数字可以高达100K。

我正在使用此数据绘制给定月份的销售趋势图表。

在模拟器上,此查询的执行时间少于0.5秒,但在设备上执行需要花费大量时间。

问题
你能指导我如何缩短这个查询的时间吗?

1 个答案:

答案 0 :(得分:2)

我确定最大的瓶颈是 SUBSTR Group By 子句并执行&处理如下所示的简单查询只花了大约0.02秒

Select purchase_date from sales where purchase_date LIKE '2012-12%' order by purchase_date asc;

所以我把它作为一个内部查询引入

Select count(purcahse_date) as count, SUBSTR(purchase_date, 0, 11) as purchase_date from
(
    Select purchase_date from sales where purchase_date LIKE '2012-12%'
)
group by purchase_date, order by purchase_date;

虽然生成的数据与初始查询相同,但时间再次飙升至5.5秒左右。

所以最后我决定咬紧牙关,我的最终解决方案是获取给定月份的所有purchase_date记录并自行处理。

所以现在代码看起来像这样

while ([resultset next])
{
    [recordsArray addObject:[resultset resultDictionary]];
}
[resultset close];

[self closeDB];
        //release the db lock at this point

int array[31];    //maximum days in a month
bzero((void *)array, 31 * sizeof(int));     //initialize the month array

for(NSDictionary * d in recordsArray)    //read the records received from the db and add daily sales count
{
    NSRange r;
    r.location = 8;
    r.length = 2;
    int dDate = [[[d objectForKey:@"purchase_date"] substringWithRange:r] intValue];
    array[dDate-1]++;
}

[recordsArray removeAllObjects];

//refDate contains @"2012-12"
for(int i=0; i<31; i++)     //now populate the final array again
{
    if(array[i] > 0)
    {
        NSDictionary * d1 = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@-%02d", refDate, i+1], @"date", [NSNumber numberWithInt:array[i]], @"count", nil];
        [recordsArray addObject:d1];
    }
}

return recordsArray;

我希望它可以帮助其他人也陷入类似的情况,或者某些数据库大师可能会建议一些比这个丑陋的解决方案更好的选择。