Для вставки около 10000 данных требуется около 60–70 секунд. Нужно ли совершать транзакции?

Я пытаюсь вставить около 10000 данных в свою базу данных. Проверьте ниже функцию для кода. Вставка всех данных занимает около минуты. Теперь я уже добавил блок в транзакцию, но мне нужно его зафиксировать или он управляется автоматически. Как я могу написать это в коде ниже?

func insertDataToDB(objects: [DataModel]) {
        removeAllData()
        createSchemaForData()
        print("Start Inserting Connectors \(Date())")
        let stmt = try? db.prepare("INSERT INTO product (connectorId, deviceId, current, status, cost, voltage, power, type, method, mode) VALUES (?,?,?,?,?,?,?,?,?,?)")
        do {
            try db.transaction {
                for product in objects {
                    try stmt?.run(product.connectorId!, product.deviceId!, product.current, product.status, product.cost, product.voltage, product.power, product.type!, product.method!, product.mode)
                }
            }
        } catch {
            print("Failed Inserting connectors: \(error.localizedDescription)")
        }
        print("End Inserting Connectors \(Date())")
    }

removeAllData() Удаляет все данные из БД перед вставкой.

createSchemaForData() При необходимости создаст схему.

struct product {
    static let table = Table("product")
    static let connectorId = Expression<String>("connectorId")
    static let deviceId = Expression<String>("deviceId")
    static let current = Expression<Double?>("current")
    static let status = Expression<String?>("status")
    static let cost = Expression<Double?>("cost")
    static let voltage = Expression<Double?>("voltage")
    static let power = Expression<Double?>("power")
    static let type = Expression<String?>("type")
    static let method = Expression<String?>("method")
    static let mode = Expression<String?>("mode")
}

person Parth Adroja    schedule 23.04.2018    source источник
comment
stackoverflow.com/a/3852082/575376   -  person juergen d    schedule 23.04.2018
comment
вы можете использовать begin transaction до начала вставки данных и после завершения вставки данных использовать commit transaction. Ссылка: stackoverflow.com/questions/14631477/   -  person Kuldeep    schedule 23.04.2018
comment
Возможный дубликат Как вставить 40 000 записей в базу данных sqlite на iPad   -  person TheTiger    schedule 23.04.2018
comment
Я согласен со всеми вами, что это выглядит как традиционная проблема с необходимостью использования транзакций, но похоже, что он использует db.transaction, который, предположительно, выполняет транзакции за него. Я думаю, что нам нужно немного почистить эту луковицу, чтобы понять, почему она не выполняет транзакцию так, как мы думаем, если это действительно проблема. Тут может быть что-то еще...   -  person Rob    schedule 23.04.2018
comment
@ Роб, ты правильно понял мой вопрос. Я уже применяю транзакцию при вставке данных. Так что есть что-то еще, что создает проблему.   -  person Parth Adroja    schedule 23.04.2018
comment
Я не уверен, что он автоматически обрабатывает BEGIN и COMMIT.   -  person TheTiger    schedule 23.04.2018
comment
Являются ли все эти поля простыми текстовыми/числовыми полями? Или одно или несколько больших полей BLOB? Я спрашиваю, потому что большие объекты в SQLite могут поставить его на колени. К вашему сведению, я подтвердил, что db.transaction выполняет необходимые действия BEGIN TRANSACTION/COMMIT (вставка 100 000 записей заняла 0,5 секунды с db.transaction и 123 секунды без), поэтому я не думаю, что рутинное наблюдение за транзакциями здесь уместно. Происходит что-то еще. Но я не могу воспроизвести проблему на основе кода в вашем вопросе, поэтому вы должны предоставить нам MCVE.   -  person Rob    schedule 23.04.2018
comment
Хорошо, @Rob, я дам вам знать, как только создам пример проекта и попытаюсь выполнить аналогичный поток.   -  person Parth Adroja    schedule 23.04.2018
comment
@Rob Я не использую поля BLOB. Все просто посмотри структуру продукта по обновленному вопросу.   -  person Parth Adroja    schedule 23.04.2018
comment
ХОРОШО. По общему признанию, я использовал SQLite.swift в качестве тонкой оболочки для SQLite API в своем тесте: робертмрайан/0e4927548b9c5cae6dd36b9697af3294. Но прежде чем я попытаюсь снова использовать ваш пример, я был бы рад, если бы вы могли подтвердить, что можете воспроизвести проблему в красивом, аккуратном MCVE, прежде чем я буду тестировать дальше. Спасибо!   -  person Rob    schedule 23.04.2018
comment
@Роб Спасибо! Я отозвал свой закрытый голос как дубликат ..., поскольку здесь обрабатываются BEGIN и COMMIT.   -  person TheTiger    schedule 23.04.2018
comment
@Rob Получил проблему и исправил. Проверьте ниже ответ.   -  person Parth Adroja    schedule 23.04.2018
comment
@ParthAdroja Рад, что ты решил эту проблему. Но это связано с той скрытой частью, о которой мы даже не можем подумать, не видя кода.   -  person TheTiger    schedule 23.04.2018
comment
@TheTiger Извините за это, потому что даже я не знал об этом, пока не сделал полную отладку кода.   -  person Parth Adroja    schedule 23.04.2018


Ответы (1)


В приведенном выше коде нет проблем, но то, что я делал неправильно, было с созданным мной одноэлементным классом.

Я использовал соединение, как показано ниже, что давало мне новое соединение каждый раз, когда я обращался к объекту db.

var db: Connection {
    let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
    return try! Connection("\(dbPath)/\(dbName)")
}

Так что улучшили код, просматривая код Роба в сути. Так что сейчас нет времени даже секунды на вставку данных.

let db: Connection = {
        let path = NSSearchPathForDirectoriesInDomains(
            .documentDirectory, .userDomainMask, true
            ).first!
        return try! Connection("\(path)/EVDataBase.sqlite")
    }()

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

person Parth Adroja    schedule 23.04.2018
comment
Декларация: static let shared = Connection("\(path)/EVDataBase.sqlite"). Использование: Connection.shared.transaction - person TheTiger; 23.04.2018
comment
Да, это вычисляемое свойство определенно вызовет описанную вами проблему. Замена его сохраненным свойством исправляет это. Хороший улов! - person Rob; 23.04.2018