gpt4 book ai didi

android - SQLite 在 Android 和 iOS 上的性能差异

转载 作者:太空宇宙 更新时间:2023-11-03 12:37:17 30 4
gpt4 key购买 nike

我正在尝试对项目的 Android 和 iOS 中的 SQLite 性能进行基准测试,与 Android 相比,iOS 平台上的性能似乎非常差。

我想要实现的是测量将多行 (5000) 插入 SQLite 数据库并在平台之间进行比较的时间。对于 Android,执行所有 5000 次插入大约需要 500 毫秒,但对于 iOS,相同的操作需要 20 多秒。怎么会这样?

这是我的 iOS 代码 fragment (插入部分),dataArray 是一个包含 5000 个随机 100 字符 NSString 的数组:

int numEntries = 5000;
self.dataArray = [[NSMutableArray alloc] initWithCapacity:numEntries];//Array for random data to write to database

//generate random data (100 char strings)
for (int i=0; i<numEntries; i++) {
[self.dataArray addObject:[self genRandStringLength:100]];
}

// Get the documents directory
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *docsDir = [dirPaths objectAtIndex:0];

// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: @"benchmark.db"]];

NSString *resultHolder = @"";

//Try to open DB, if file not present, create it
if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK){

sql = @"CREATE TABLE IF NOT EXISTS BENCHMARK(ID INTEGER PRIMARY KEY AUTOINCREMENT, TESTCOLUMN TEXT)";

//Create table
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) == SQLITE_OK){
NSLog(@"DB created");
}else{
NSLog(@"Failed to create DB");
}

//START: INSERT BENCHMARK
NSDate *startTime = [[NSDate alloc] init];//Get timestamp for insert-timer

//Insert values in DB, one by one
for (int i = 0; i<numEntries; i++) {
sql = [NSString stringWithFormat:@"INSERT INTO BENCHMARK (TESTCOLUMN) VALUES('%@')",[self.dataArray objectAtIndex:i]];
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) == SQLITE_OK){
//Insert successful
}
}

//Append time consumption to display string
resultHolder = [resultHolder stringByAppendingString:[NSString stringWithFormat:@"5000 insert ops took %f sec\n", [startTime timeIntervalSinceNow]]];

//END: INSERT BENCHMARK

安卓代码 fragment :

           // SETUP
long startTime, finishTime;

// Get database object
BenchmarkOpenHelper databaseHelper = new BenchmarkOpenHelper(getApplicationContext());
SQLiteDatabase database = databaseHelper.getWritableDatabase();

// Generate array containing random data
int rows = 5000;
String[] rowData = new String[rows];
int dataLength = 100;

for (int i=0; i<rows; i++) {
rowData[i] = generateRandomString(dataLength);
}

// FIRST TEST: Insertion
startTime = System.currentTimeMillis();

for(int i=0; i<rows; i++) {
database.rawQuery("INSERT INTO BENCHMARK (TESTCOLUMN) VALUES(?)", new String[] {rowData[i]});
}

finishTime = System.currentTimeMillis();
result += "Insertion test took: " + String.valueOf(finishTime-startTime) + "ms \n";
// END FIRST TEST

最佳答案

在 iOS 上,除了 StilesCrisis 讨论的 BEGIN/COMMIT 更改之外,它提供了最显着的性能差异,如果您想进一步优化 iOS 性能,考虑一次准备 SQL,然后重复调用 sqlite3_bind_textsqlite3_stepsqlite3_reset。在这种情况下,它似乎使速度大约快了一倍。

所以,这是我使用 sqlite3_exec 对现有 iOS 逻辑的再现(它每次都使用 stringWithFormat%@ 手动构建 SQL ):

- (void)insertWithExec
{
NSDate *startDate = [NSDate date];

NSString *sql;

if (sqlite3_exec(database, "BEGIN", NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: begin failed: %s", __FUNCTION__, sqlite3_errmsg(database));

for (NSString *value in dataArray)
{
sql = [NSString stringWithFormat:@"INSERT INTO BENCHMARK (TESTCOLUMN) VALUES('%@')", value];
if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: exec failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}

if (sqlite3_exec(database, "COMMIT", NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: commit failed: %s", __FUNCTION__, sqlite3_errmsg(database));

NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startDate];

// log `elapsed` here
}

这是代码的优化再现,我只准备了一次 SQL,然后使用 sqlite3_bind_text 将我们的数据绑定(bind)到 SQL 中相同的 ? 占位符使用的安卓代码:

- (void)insertWithBind
{
NSDate *startDate = [NSDate date];

if (sqlite3_exec(database, "BEGIN", NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: begin failed: %s", __FUNCTION__, sqlite3_errmsg(database));

sqlite3_stmt *statement;

NSString *sql = @"INSERT INTO BENCHMARK (TESTCOLUMN) VALUES(?)";

if (sqlite3_prepare_v2(database, [sql UTF8String], -1, &statement, NULL) != SQLITE_OK)
NSLog(@"%s: prepare failed: %s", __FUNCTION__, sqlite3_errmsg(database));

for (NSString *value in dataArray)
{
if (sqlite3_bind_text(statement, 1, [value UTF8String], -1, NULL) != SQLITE_OK)
NSLog(@"%s: bind failed: %s", __FUNCTION__, sqlite3_errmsg(database));

if (sqlite3_step(statement) != SQLITE_DONE)
NSLog(@"%s: step failed: %s", __FUNCTION__, sqlite3_errmsg(database));

if (sqlite3_reset(statement) != SQLITE_OK)
NSLog(@"%s: reset failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}

sqlite3_finalize(statement);

if (sqlite3_exec(database, "COMMIT", NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: commit failed: %s", __FUNCTION__, sqlite3_errmsg(database));

NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startDate];

// log `elapsed` here
}

在我的 iPhone 5 上,使用您的 sqlite3_exec 逻辑(我的 insertWithExec 方法)插入 5,000 条记录需要 280-290 毫秒,插入相同的记录需要 110-127 毫秒5,000 条记录,包含 sqlite3_bind_textsqlite3_stepsqlite3_reset(我的 insertWithBind 方法)。我的数字与你的数字不相上下(不同的设备,插入不同的 dataValues 对象,我是在后台队列中完成的,等等),但值得注意的是,准备时花费的时间不到一半SQL 语句一次,然后只重复 bind、step 和 reset 调用。

查看 Android 代码,我注意到您正在使用 ? 占位符,所以我假设它也在幕后执行 sqlite3_bind_text (虽然我不知道不知道它是准备一次然后每次都绑定(bind)/步进/重置,还是每次都重新准备;可能是后者)。


顺便说一句,作为一般经验法则,您应该始终使用 ? 占位符,就像您在 Android 中所做的那样,而不是使用 stringWithFormat 手动构建 SQL ,因为它使您无需手动转义数据中的撇号,保护您免受 SQL 注入(inject)攻击等。

关于android - SQLite 在 Android 和 iOS 上的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16094503/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com