Подтвердить что ты не робот

Самый быстрый способ вставить много строк в sqlite db на iPhone

Может кто-нибудь объяснить, что лучший способ вставить много данных на iPhone с помощью FMDB? Я вижу такие вещи, как использование команды beginTransaction. Я честно не уверен, что это или setShouldCacheStatements. Я следовал тому коду, который сделал мой коллега до сих пор, и это выглядит так:

BOOL oldshouldcachestatements = _db.shouldCacheStatements;
[_db setShouldCacheStatements:YES];
[_db beginTransaction];
NSString *insertQuery = [[NSString alloc] initWithFormat:@"INSERT INTO %@ values(null, ?, ?, ?, ?, ?, ?, ?);", tableName];
[tableName release];
BOOL success;

bPtr += 2;
int *iPtr = (int *)bPtr;
int numRecords = *iPtr++;

for (NSInteger record = 0; record < numRecords; record++) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // Some business logic to read the binary stream  

    NSNumber *freq = aFreq > 0 ? [NSNumber numberWithDouble:100 * aFreq / 32768]: [NSNumber numberWithDouble:-1.0];

    // these fields were calculated in the business logic section
    success = [_db executeUpdate:insertQuery,
               cID,                                                                                                   
               [NSNumber numberWithInt:position],                                                                       
               [NSString stringWithFormat:@"%@%@", [self stringForTypeA:typeA], [self stringForTypeB:typeB]],     // methods are switch statements that look up the decimal number and return a string
               [NSString stringWithFormat:@"r%i", rID],                                                               
               [self stringForOriginal:original],                                                                    
               [self stringForModified:modified],                                                                    
               freq];

    [pool drain];
}
[outerPool drain];

[_db commit];
[_db setShouldCacheStatements:oldshouldcachestatements];

Я могу сделать это быстрее всего? Является ли написанием ограничение sqlite? Я видел это: http://www.sqlite.org/faq.html#q19 и не был уверен, что эта реализация была лучшей с fmdb, или если была какая-то другая вещь, которую я могу сделать, Некоторые другие коллеги упоминали что-то о массовых вставках и оптимизируют это, но я не уверен, что это означает, так как это моя первая встреча с sqlite. Какие мысли или направления я могу исследовать? Спасибо!

4b9b3361

Ответ 1

Прежде всего, в большинстве случаев вам не нужно беспокоиться о производительности sqlite3, если вы не используете его полностью неправильно.

Следующие показатели повышают производительность операторов INSERT:

Сделки

Как вы уже упоминали, транзакции являются наиболее важной функцией. Особенно, если у вас есть большое количество запросов, транзакция будет ускорить ваш INSERT на ~ 10 раз.

Конфигурация PRAGMA

Sqlite3 предоставляет несколько механизмов, которые предотвращают повреждение вашей базы данных в худших случаях. В некоторых сценариях это не требуется. В других это абсолютно необходимо. Следующие команды sqlite3 могут ускорить выполнение операторов INSERT. Обычный сбой вашего приложения не повредит базу данных, но может произойти сбой ОС.

PRAGMA synchronous=OFF -- may cause corruption if the OS fails
PRAGMA journal_mode=MEMORY -- Insert statements will be written to the disk at the end of the transaction
PRAGMA cache_size = 4000 -- If your SELECTs are really big, you may need to increase the cache
PRAGMA temp_store=MEMORY -- Attention: increases RAM use

Деактивировать индикаторы

Любой индекс SQL замедляет инструкцию INSERT. Проверьте, есть ли у вашей таблицы некоторые индексы:

.indices <table_name>

Если да, DROP INDEX и CREATE после транзакции.

One Select

Я не вижу способ использования BULK-вставки при создании новых данных. Однако вы можете собирать данные и просто выполнять один оператор INSERT. Это может резко увеличить вашу производительность, но также повышает вероятность сбоя (например, синтаксис). Один хак встречает другой взлом: поскольку sqlite3 не поддерживает это напрямую, вы должны использовать команду UNION для сбора всех инструкций вставки.

INSERT INTO 'tablename'
      SELECT 'data1' AS 'column1', 'data2' AS 'column2'
UNION SELECT 'data3', 'data4'
UNION SELECT 'data5', 'data6'
UNION SELECT 'data7', 'data8'

Кэширование операторов

Я бы посоветовал избежать использования кэширования инструкций, так как есть нефиксированная проблема с этой функцией (и насколько я знаю, это не влияет на производительность резко).

Управление памятью

Последнее, что я хотел бы упомянуть, это ObjC. По сравнению с основными операциями, управление памятью требует очень много времени. Возможно, вы могли бы избежать некоторых stringWithFormat: или numberWithDouble:, подготовив эту переменную вне цикла.

Резюме

В целом, я не думаю, что у вас будет проблема со скоростью sqlite3, если вы просто используете транзакции.

Ответ 2

Мне было очень сложно найти конкретный пример кода о том, как быстро вставить много строк. После много экспериментов с FMDB и с помощью ответа выше, вот что я использую в данный момент:

[_objectController.dbQueue inDatabase:^(FMDatabase *db)
{
    [db open];
    [db setShouldCacheStatements:YES];

    NSArray *documentsJSONStream = responseObject[@"details"][@"stream"];

    static NSString *insertSQLStatment = @"INSERT INTO documents (`isShared`,`thumbnailURLString`,`userID`,`version`,`timestamp`,`tags`,`title`,`UDID`,`username`,`documentURLString`,`shareURLString`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    [db beginTransaction];
    for (NSDictionary *dJ in documentsJSONStream)
    {
        [db executeUpdate:insertSQLStatment withArgumentsInArray:@[dJ[@"isShared"],dJ[@"thumbnailURLString"],dJ[@"userID"],dJ[@"version"],dJ[@"timestamp"],dJ[@"tags"],dJ[@"title"],dJ[@"UDID"],dJ[@"username"],dJ[@"documentURLString"],dJ[@"shareURLString"]]];
    }
    [db commit];
    [db close];
 }];

Использование inTransaction дало мне странный FMDB, это не открытые ошибки. Если есть предложения по улучшению этого, сообщите мне.