數(shù)據(jù)清理:
和PostgreSQL中的VACUUM命令相比鸳君,他們的功能以及實現(xiàn)方式非常相似留晚,不同的是PostgreSQL提供了更細的粒度榜聂,而SQLite只能將該命令作用于數(shù)據(jù)庫渐夸,無法再精確到數(shù)據(jù)庫中指定的數(shù)據(jù)表或者索引撕彤,然而這一點恰恰是PostgreSQL可以做到的。
當某個數(shù)據(jù)庫中的一個或多個數(shù)據(jù)表存在大量的插入榆苞、更新和刪除等操作時稳衬,將會有大量的磁盤空間被已刪除的數(shù)據(jù)所占用,在沒有執(zhí)行VACUUM命令之前坐漏,SQLite并沒有將它們歸還于操作系統(tǒng)薄疚。由于該類數(shù)據(jù)表中的數(shù)據(jù)存儲非常分散,因此在查詢時赊琳,無法得到更好的批量IO讀取效果街夭,從而影響了查詢效率。
在SQLite中躏筏,僅支持清理當前連接中的主數(shù)據(jù)庫板丽,而不能清理其它Attached數(shù)據(jù)庫。VACUUM命令在完成數(shù)據(jù)清理時采用了和PostgreSQL相同的策略寸士,即創(chuàng)建一個和當前數(shù)據(jù)庫文件相同大小的新數(shù)據(jù)庫文件檐什,之后再將該數(shù)據(jù)庫文件中的數(shù)據(jù)有組織的導(dǎo)入到新文件中碴卧,其中已經(jīng)刪除的數(shù)據(jù)塊將不會被導(dǎo)入弱卡,在完成導(dǎo)入后,收縮新數(shù)據(jù)庫文件的尺寸到適當?shù)拇笮∽〔帷T撁畹膱?zhí)行非常簡單婶博,如:
sqlite> VACUUM;
- (void)vacuumDB {
NSArray *databaseInfos;
@synchronized(_databaseInfos) {
databaseInfos = _databaseInfos.allValues;
}
for (GYDatabaseInfo *databaseInfo in databaseInfos) {
[databaseInfo.databaseQueue syncInDatabase:^(FMDatabase *db) {
if (databaseInfo.timer) {
dispatch_suspend(databaseInfo.timer);
[db commit];
databaseInfo.needCommitTransaction = NO;
}
[db executeStatements:@"VACUUM"];
if (databaseInfo.timer) {
[db beginTransaction];
dispatch_resume(databaseInfo.timer);
}
}];
}
}
數(shù)據(jù)分析:
和PostgreSQL非常相似,SQLite中的ANALYZE命令也同樣用于分析數(shù)據(jù)表和索引中的數(shù)據(jù)荧飞,并將統(tǒng)計結(jié)果存放于SQLite的內(nèi)部系統(tǒng)表中凡人,以便于查詢優(yōu)化器可以根據(jù)分析后的統(tǒng)計數(shù)據(jù)選擇最優(yōu)的查詢執(zhí)行路徑,從而提高整個查詢的效率叹阔。見如下示例:
--如果在ANALYZE命令之后沒有指定任何參數(shù)挠轴,則分析當前連接中所有Attached數(shù)據(jù)庫中的表和索引。
sqlite> ANALYZE;
--如果指定數(shù)據(jù)庫作為ANALYZE的參數(shù)耳幢,那么該數(shù)據(jù)庫下的所有表和索引都將被分析并生成統(tǒng)計數(shù)據(jù)岸晦。
sqlite> ANALYZE main;
--如果指定了數(shù)據(jù)庫中的某個表或索引為ANALYZE的參數(shù)欧啤,那么該表和其所有關(guān)聯(lián)的索引都將被分析。
sqlite> ANALYZE main.testtable;
sqlite> ANALYZE main.testtable_idx2;
- (void)synchronizeDB:(NSString *)dbName {
@synchronized(_databaseInfos) {
GYDatabaseInfo *databaseInfo = [_databaseInfos objectForKey:dbName];
[databaseInfo.databaseQueue syncInDatabase:^(FMDatabase *db) {
if (databaseInfo.timer) {
dispatch_source_cancel(databaseInfo.timer);
databaseInfo.timer = nil;
[db commit];
}
if (databaseInfo.writeCount >= 500) {
[db executeStatements:@"ANALYZE"];
databaseInfo.writeCount = 0;
}
}];
@synchronized(databaseInfo.updatedTables) {
[databaseInfo.databaseQueue close];
[databaseInfo.updatedTables removeAllObjects];
}
[self.writeCounts setObject:@(databaseInfo.writeCount) forKey:dbName];
NSData *data = [NSPropertyListSerialization dataWithPropertyList:self.writeCounts
format:NSPropertyListBinaryFormat_v1_0
options:0
error:nil];
[data writeToFile:[GYDBRunner pathForAnalyzeStatistics] atomically:YES];
}
}