数据库操作优化

  • 数据库耗时操作

    • 主要是往数据库执行写操作
    // 插入数据
    [db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), @"fancy", @(15.0), @"derain"];
    
    // 更新数据
    [db executeUpdate:@"UPDATE t_PetInfo SET name = ?", @"fffffancy"];
    
    // 删除数据
    [db executeUpdate:@"DELETE FROM t_PetInfo WHERE petNo > ?", @(20)];
    
  • 耗时操作优化

    • 利用事务提交 可以有效的减少耗时

    • 在子线程处理耗时操作

耗时操作实验
  • 插入数据

    • 开启事务耗时: 0.097206
    • 不开启事务耗时:38.051225
    • 插入10000条数据, 不开启事务耗时是开启事务的391
    
    // 1.0 开启事务
    CGFloat beginTime = [NSDate timeIntervalSinceReferenceDate];
    
    [db beginTransaction];
    for (NSInteger i = 0; i < 10000; i++) {
        
        NSString *name = (i % 2) ? @"fancy" : nil;
         [db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), name, @(15.0), @"derain"];
    }
    [db commit];
     CGFloat endTime = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"%f", endTime - beginTime); // 耗时: 0.097206
    
    // 2.0 不开启事务
    CGFloat beginTime = [NSDate timeIntervalSinceReferenceDate];
    
    for (NSInteger i = 0; i < 10000; i++) {
        
        NSString *name = (i % 2) ? @"fancy" : nil;
         [db executeUpdate:@"INSERT INTO t_PetInfo(petNo, age, name, weight, hoster) VALUES(?, ?, ?, ?, ?);", @(i), @(2), name, @(15.0), @"derain"];
    }
    CGFloat endTime = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"%f", endTime - beginTime); // 耗时: 38.051225
    
    
  • 查询耗时实验
    • 开启事务耗时: 0.037018
    • 不开启事务耗时:0.037175
    • 两者基本一样, 因为读操作只需数据库一次, 频繁的开启事务, 提交事务
    • 当然, 当有大量读操作时, 依旧推荐使用事务
    
    // 开启事务
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    [db beginTransaction];
    
    for (NSInteger i = 0; i < 1000; i++) {
        
       FMResultSet *result = [db executeQuery:@"SELECT * FROM t_PetInfo;"];
    }

    [db commit];
    CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2);
    
    [db close];
    

// 不开启事务
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
      for (NSInteger i = 0; i < 1000; i++) {
        
       FMResultSet *result = [db executeQuery:@"SELECT * FROM t_PetInfo;"];
    }

   CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2);
    
    [db close];
  • 更新操作耗时实验
    • 开启事务耗时: 5.725228
    • 不开启事务耗时:15.122401
    • 因为表内有10000条数据, 又执行修改100次, 耗时都较多
// 开启事务
    // 1.0 创建数据库
    NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"tmps.db"];
    
    FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
    
    [db open];

    [db beginTransaction];
    
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    for (NSInteger i = 0; i < 1000; i++) {
        
        [db executeUpdate:@"UPDATE t_PetInfo SET name = ?, age = ?;", @"funny", @(i)];
    }

    [db commit];
    CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2); // 5.725228
    
    [db close];
   // 不开启事务
    
    NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"tmps.db"];
    
    FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
    
    [db open];
    
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    for (NSInteger i = 0; i < 1000; i++) {
        
        [db executeUpdate:@"UPDATE t_PetInfo SET name = ?, age = ?;", @"funny", @(i)];
    }
    
    CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2); // 15.122401
     
    [db close];
  • 删除数据耗时实验
    • 开启事务耗时: 0.608012
    • 不开启事务耗时:4.768991
    // 开启事务
    NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"tmps.db"];
    
    FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
    
    [db open];

    [db beginTransaction];
    
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    for (NSInteger i = 0; i < 1000; i++) {
        
        [db executeUpdate:@"DELETE FROM t_PetInfo WHERE petNo = ?", @(i)];
    }
    
    [db commit];
    CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2);
    
    [db close]; // 0.608012
    NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"tmps.db"];
    
    FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
    
    [db open];

   // [db beginTransaction];
    
    CGFloat beginTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    for (NSInteger i = 0; i < 1000; i++) {
        
        [db executeUpdate:@"DELETE FROM t_PetInfo WHERE petNo = ?", @(i)];
    }
    
   //[db commit];
    CGFloat endTime2 = [NSDate timeIntervalSinceReferenceDate];
    
    NSLog(@"time2 - %f", endTime2 - beginTime2);
    
    [db close]; // 4.768991
  • 在子线程处理耗时操作

    • FMDatabase是多线程不安全的
    • 推荐使用FMDatabaseQueue, 使用全局单列, 在子线成执行耗时操作
  • 耗时来由

    • 数据库以文件的形式存在磁盘中, 每次访问时都要打开一次文件,一切的数据库操作其实都会转化为对文件的操作
    • 如果对数据库进行大量的写操作, 则耗时较大
    • 每次执行sqlite3_exec, 默认都会开启一个隐藏事务, 当执行完操作, 就会提交事务; 每次都会操作文件(数据库)
    int sqlite3_exec(
    sqlite3* ppDb,                             /* An open database */
    const char *sql,                           /* SQL to be evaluated */
    int (*callback)(void*,int,char**,char**),  /* Callback function */
    void *,                                    /* 1st argument to callback */
    char **errmsg                              /* Error msg written here */
    );
    
  • 手动开启事务解如何解决耗时操作?

    • 当我们手动开启事务时, 系统就不再默认开启隐藏事务

    • 开始事务后,进行的大量操作语句都保存在内存中当提交时才全部写入数据库,此时,数据库文件也只用打开一次;

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