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

}

你可能感兴趣的:(真机iOS fmdb sqlite插入数据慢)