真机iOS fmdb sqlite插入数据慢

fmdb sqlite插入数据慢


之前使用FMDB加载一个全国的行政区划的数据库表到客户端,好让用户在选择收获地址时在本地加载,提高用户的使用体验,在模拟器上跑时非常方便,但在测试时非常慢,真机加载时格外慢,加载8万多条的数据差不多要半个小时,这简直不能忍受,后来查找了很多资料,发现只要添加了事务就好了, 一行代码提升了好几十倍,原本半小时才可以的现在一分钟内就好了,10万条数据测试结果如下(结论,开启事务普通出入数据最快):

模拟器上的结果:(时间差别不大)
2017-07-25 16:02:06.233 TestFMDB[66270:4375010] *** 创建数据花费时间 0.409968 s
2017-07-25 16:02:59.004 TestFMDB[66270:4375010] *** 普通方式插入数据花费时间 52.770025 s
2017-07-25 16:02:59.004 TestFMDB[66270:4375010] *** address fmdb 加载数据库结束

2017-07-25 16:02:06.233 TestFMDB[66270:4375010] *** 创建数据花费时间 0.409968 s
2017-07-25 16:02:59.004 TestFMDB[66270:4375010] *** 普通方式插入数据花费时间 52.770025 s
2017-07-25 16:02:59.004 TestFMDB[66270:4375010] *** address fmdb 加载数据库结束

2017-07-25 16:08:38.285 TestFMDB[66420:4379160] *** 创建数据花费时间 0.433273 s
2017-07-25 16:08:51.874 TestFMDB[66420:4379157] *** 多线程开启事务方式插入数据花费时间 13.587659 s
2017-07-25 16:09:03.745 TestFMDB[66420:4379158] *** 多线程开启事务方式插入数据花费时间 25.459356 s
2017-07-25 16:09:23.915 TestFMDB[66420:4379222] *** 多线程开启事务方式插入数据花费时间 45.629394 s
2017-07-25 16:09:40.919 TestFMDB[66420:4379211] *** 多线程开启事务方式插入数据花费时间 62.632683 s

真机测试结果(没有重现我项目中不开启事务特别慢的情况)
// 普通插入数据
2017-07-25 16:23:21.120660+0800 TestFMDB[2152:677046] *** 创建数据花费时间 1.374888 s
2017-07-25 16:24:14.512719+0800 TestFMDB[2152:677046] *** 普通方式插入数据花费时间 53.391885 s
2017-07-25 16:24:14.512885+0800 TestFMDB[2152:677046] *** address fmdb 加载数据库结束

// 普通开启事务的结果
2017-07-25 16:21:22.480394+0800 TestFMDB[2147:676024] *** 创建数据花费时间 1.359878 s
2017-07-25 16:22:00.316775+0800 TestFMDB[2147:676024] *** 开启事务方式插入数据花费时间 37.836121 s
2017-07-25 16:22:00.316933+0800 TestFMDB[2147:676024] *** address fmdb 加载数据库结束

// 开启4个线程的结果
2017-07-25 16:14:07.000092+0800 TestFMDB[2135:671904] *** 创建数据花费时间 1.484458 s
2017-07-25 16:14:16.818597+0800 TestFMDB[2135:671902] *** 线程1开启事务方式插入数据花费时间 9.818329 s
2017-07-25 16:14:26.386697+0800 TestFMDB[2135:671903] *** 线程2开启事务方式插入数据花费时间 19.386441 s
2017-07-25 16:14:36.702309+0800 TestFMDB[2135:671900] *** 线程3开启事务方式插入数据花费时间 29.702041 s
2017-07-25 16:14:47.890248+0800 TestFMDB[2135:671901] *** 线程4开启事务方式插入数据花费时间 40.889873 s

开启2个线程的结果
2017-07-25 16:15:52.293433+0800 TestFMDB[2137:672875] *** 创建数据花费时间 2.423719 s
2017-07-25 16:16:13.158949+0800 TestFMDB[2137:672877] *** 线程1开启事务方式插入数据花费时间 20.865313 s
2017-07-25 16:16:32.692071+0800 TestFMDB[2137:672876] *** 线程2开启事务方式插入数据花费时间 40.398287 s

开启2个线程不开启事务的结果
2017-07-25 16:17:20.354732+0800 TestFMDB[2140:673793] *** 创建数据花费时间 1.563348 s
2017-07-25 16:17:47.615129+0800 TestFMDB[2140:673794] *** 线程1开启事务方式插入数据花费时间 27.260129 s
2017-07-25 16:18:16.670929+0800 TestFMDB[2140:673796] *** 线程2开启事务方式插入数据花费时间 56.316027 s

具体代码如下:

#pragma mark - ###### 将数据存入数控库
- (void)testInsertDB
{
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 创建测试数据
        NSTimeInterval createDataBegin = [[NSDate date] timeIntervalSince1970];
        NSMutableArray *arrayM = [NSMutableArray array];
        for (int i=0; i<10*10000; i++) {
            NSMutableDictionary *item = [NSMutableDictionary dictionary];
            item[@"addr_id"] = [NSString stringWithFormat:@"addr_id_%d",i];
            item[@"parent_addr_id"] = [NSString stringWithFormat:@"parent_addr_id_%d",i];
            item[@"addr_value"] = [NSString stringWithFormat:@"addr_value_%d",i];
            [arrayM addObject:item];
        }
        NSTimeInterval createDataEnd = [[NSDate date] timeIntervalSince1970];
        CGFloat createDataCost = (createDataEnd - createDataBegin);
        NSLog(@"*** 创建数据花费时间 %f s",createDataCost);
        // 调用
        // 普通插入
        [weakSelf normalSaveData2LocalDataBaseWithNSArray:arrayM];
        // 开启事务插入
        //[weakSelf transationSaveData2LocalDataBaseWithNSArray:arrayM];
        // 开启多个Queue和事务插入
        //[weakSelf mutalQueueSaveData2LocalDataBaseWithNSArray:arrayM];
    });
    
}
#pragma mark - ******** 普通一条一条插入
- (void)normalSaveData2LocalDataBaseWithNSArray:(NSArray *)addressList
{
        NSTimeInterval insertDataBegin = [[NSDate date] timeIntervalSince1970];
        // 获得Documents目录路径
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        
        // 文件路径
        NSString *filePath = [documentsPath stringByAppendingPathComponent:@"testAddress.sqlite"];
        
        // 实例化FMDataBase对象
        
        FMDatabase *db = [FMDatabase databaseWithPath:filePath];
        
        [db open];
        NSString *dropSql = @"DROP TABLE t_test_address;";
        [db executeUpdate:dropSql];
        // 初始化数据表
        NSString *createSql = @"CREATE TABLE IF NOT EXISTS 't_test_address' ('id' INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL ,'addr_id' VARCHAR(255),'parent_addr_id' VARCHAR(255),'addr_value' VARCHAR(255)) ";
        
        [db executeUpdate:createSql];
    
        for (NSDictionary *item in addressList) {
            // 初始化数据表
            NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
            BOOL insertRes = [db executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
            
            
        }
        NSTimeInterval insertDataEnd = [[NSDate date] timeIntervalSince1970];
        CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
        NSLog(@"*** 普通方式插入数据花费时间 %f s",insertDataCost);
        NSLog(@"*** address fmdb 加载数据库结束");

}
#pragma mark - ******** 开启事务插入
- (void)transationSaveData2LocalDataBaseWithNSArray:(NSArray *)addressList
{
    NSTimeInterval insertDataBegin = [[NSDate date] timeIntervalSince1970];
    // 获得Documents目录路径
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    // 文件路径
    NSString *filePath = [documentsPath stringByAppendingPathComponent:@"testAddress.sqlite"];
    
    // 实例化FMDataBase对象
    
    FMDatabase *db = [FMDatabase databaseWithPath:filePath];
    
    [db open];
    NSString *dropSql = @"DROP TABLE t_test_address;";
    [db executeUpdate:dropSql];
    // 初始化数据表
    NSString *createSql = @"CREATE TABLE IF NOT EXISTS 't_test_address' ('id' INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL ,'addr_id' VARCHAR(255),'parent_addr_id' VARCHAR(255),'addr_value' VARCHAR(255)) ";
    
    [db executeUpdate:createSql];
    
    
    [db beginTransaction];
    for (NSDictionary *item in addressList) {
        // 初始化数据表
        NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
        BOOL insertRes = [db executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
        
        
    }
    [db commit];
    NSTimeInterval insertDataEnd = [[NSDate date] timeIntervalSince1970];
    CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
    NSLog(@"*** 开启事务方式插入数据花费时间 %f s",insertDataCost);
    NSLog(@"*** address fmdb 加载数据库结束");

}
#pragma mark - ******** 多线程务事务插入
- (void)mutalQueueSaveData2LocalDataBaseWithNSArray:(NSArray *)addressList
{
    NSTimeInterval insertDataBegin = [[NSDate date] timeIntervalSince1970];
    // 获得Documents目录路径
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    // 文件路径
    NSString *filePath = [documentsPath stringByAppendingPathComponent:@"testAddress.sqlite"];
    
    // 实例化FMDataBase对象
    
    FMDatabase *db = [FMDatabase databaseWithPath:filePath];
    
    [db open];
    NSString *dropSql = @"DROP TABLE t_test_address;";
    [db executeUpdate:dropSql];
    // 初始化数据表
    NSString *createSql = @"CREATE TABLE IF NOT EXISTS 't_test_address' ('id' INTEGER PRIMARY KEY AUTOINCREMENT  NOT NULL ,'addr_id' VARCHAR(255),'parent_addr_id' VARCHAR(255),'addr_value' VARCHAR(255)) ";
    
    
    
    __block NSTimeInterval insertDataEnd = [[NSDate date] timeIntervalSince1970];
    
    
     //创建连个线程(模拟多线程操作)
     dispatch_queue_t q1 = dispatch_queue_create("queue1", NULL);
     dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL);
     dispatch_queue_t q3 = dispatch_queue_create("queue3", NULL);
     dispatch_queue_t q4 = dispatch_queue_create("queue4", NULL);
    
     FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:filePath];
     NSInteger range = addressList.count / 2;
     //线程一
     dispatch_async(q1, ^{
     
         [queue inDatabase:^(FMDatabase *db2) {
             [db2 beginTransaction];
             for (NSInteger i = range*0; i < range*1;i++) {
                 NSDictionary *item = addressList[i];
                 // 初始化数据表
                 NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
                 BOOL insert = [db2 executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
             }
             [db2 commit];
             NSTimeInterval insertDataEnd1 = [[NSDate date] timeIntervalSince1970];
             if (insertDataEnd1 > insertDataEnd) {
                 insertDataEnd = insertDataEnd1;
                 CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
                 NSLog(@"*** 线程1开启事务方式插入数据花费时间 %f s",insertDataCost);
                 
             }
        }];
        
     });
     
     //线程二
     dispatch_async(q2, ^{
         [queue inDatabase:^(FMDatabase *db2) {
             [db2 beginTransaction];
             for (NSInteger i = range*1; i < addressList.count; i++) {
                 NSDictionary *item = addressList[i];
                 // 初始化数据表
                 NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
                 BOOL insert = [db2 executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
             }
             [db2 commit];
             NSTimeInterval insertDataEnd2 = [[NSDate date] timeIntervalSince1970];
             if (insertDataEnd2 > insertDataEnd) {
                 insertDataEnd = insertDataEnd2;
                 CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
                 NSLog(@"*** 线程2开启事务方式插入数据花费时间 %f s",insertDataCost);
                 
             }
         }];
     });
    /*
     //线程三
     dispatch_async(q3, ^{
         [queue inDatabase:^(FMDatabase *db2) {
             [db2 beginTransaction];
             for (NSInteger i = range*2; i < range*3; i++) {
                 NSDictionary *item = addressList[i];
                 // 初始化数据表
                 NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
                 BOOL insert = [db2 executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
             }
             [db2 commit];
             NSTimeInterval insertDataEnd3 = [[NSDate date] timeIntervalSince1970];
             if (insertDataEnd3 > insertDataEnd) {
                 insertDataEnd = insertDataEnd3;
                 CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
                 NSLog(@"*** 线程3开启事务方式插入数据花费时间 %f s",insertDataCost);
                 
             }
         }];
     });
    
     //线程四
     dispatch_async(q4, ^{
         [queue inDatabase:^(FMDatabase *db2) {
             [db2 beginTransaction];
             for (NSInteger i = range*3; i < addressList.count; i++) {
                 NSDictionary *item = addressList[i];
                 // 初始化数据表
                 NSString *insertSql = @"INSERT INTO t_address (addr_id, parent_addr_id,addr_value) VALUES (?,?,?)";
                 BOOL insert = [db2 executeUpdate:insertSql withArgumentsInArray:@[item[@"addr_id"],item[@"parent_addr_id"],item[@"addr_value"]]];
             }
             [db2 commit];
             NSTimeInterval insertDataEnd4 = [[NSDate date] timeIntervalSince1970];
             if (insertDataEnd4 > insertDataEnd) {
                 insertDataEnd = insertDataEnd4;
                 CGFloat insertDataCost = (insertDataEnd - insertDataBegin);
                 NSLog(@"*** 线程4开启事务方式插入数据花费时间 %f s",insertDataCost);
                 
             }
         }];
     });
    */

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容