1


我正在尝试执行一个包含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 秒,但第一次调用 [resultset next] 并且时间会增加到 7 秒以上。

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

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

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

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

4

1 回答 1

2

我确定最大的瓶颈是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 可能会提出比这个丑陋的解决方案更好的选择。

于 2013-01-04T16:16:45.763 回答