美文网首页iOS开发
真机iOS fmdb sqlite插入数据慢

真机iOS fmdb sqlite插入数据慢

作者: 独孤流 | 来源:发表于2017-07-25 16:28 被阅读33次

    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);
                     
                 }
             }];
         });
        */
    
    }
    

    相关文章

      网友评论

        本文标题:真机iOS fmdb sqlite插入数据慢

        本文链接:https://www.haomeiwen.com/subject/ayiwkxtx.html