【问题标题】:iPhone SQLite (FMDB) query takes excessive timeiPhone SQLite (FMDB) 查询耗时过长
【发布时间】:2012-12-18 22:49:18
【问题描述】:


我正在尝试执行一个包含 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 的查询(如

)来修改查询以删除 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 秒,但第一次调用 [resultset next] 时间会达到 7 秒以上。

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

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

在模拟器上,此查询的执行时间不到 0.5 秒,但在设备上则需要很多时间。

问题
您能指导我如何缩短此查询的时间吗?

【问题讨论】:

    标签: iphone sqlite query-optimization fmdb


    【解决方案1】:

    我确定最大的瓶颈是 SUBSTRGroup 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;
    

    我希望它可以帮助其他也陷入类似情况的人,或者某些 db guru 可能会提出比这个丑陋的解决方案更好的替代方案。

    【讨论】:

      猜你喜欢
      • 2019-08-02
      • 1970-01-01
      • 2011-11-03
      • 2015-10-23
      • 2012-11-04
      • 2013-07-24
      • 2015-09-08
      • 2016-11-04
      相关资源
      最近更新 更多