Sqlite3 вставляет в неиндексированную таблицу, занимая больше времени по мере увеличения таблицы - PullRequest
1 голос
/ 25 сентября 2011

Не вдаваясь в подробности, у меня в приложении для iOS есть процесс, который анализирует XML и вставляет (иногда до 10 или 100 с) тысячи записей в таблицу Sqlite3.

Для ускорения у меня нет индексов в таблице, и я сначала вставляю записи во временную таблицу в памяти, а затем перемещаю их в финальную таблицу партиями по 400. Ни во временной таблице, ни в таблице файловой системы нет индексов. .

Проблема, которую я замечаю, состоит в том, что в начале процесса требуется около 10-й секунды, чтобы сбросить 400 записей на диск. Затем с каждым сбросом это занимает все больше и больше времени, а через минуту или две требуется 3 секунды, чтобы сбросить 400 записей. Чем дольше, тем дольше. Каждый сброс занимает примерно на 1–2 десятых секунды дольше, чем предыдущий.

Поскольку я не использую никаких индексов, кто-нибудь может объяснить, почему это происходит, и порекомендовать решение?

Обновление 1: Я попытался установить PRAGMA syncronous = OFF;, и хотя это немного ускорило процесс, оно все равно стало на долю секунды медленнее с каждым INSERT SELECT до точки, где оно будет кратно секундам для каждого сброса после нескольких тысяч строк. Я продолжу пробовать другие оптимизации, чтобы посмотреть, смогу ли я добраться до сути этого ...

Обновление 2: Разъяснение того, что я делаю: я вставляю записи, когда они анализируются, во временную таблицу, которая находится в памяти, до тех пор, пока счетчик не достигнет 400, как подсчитывается с помощью int в коде Objective-C. Как только количество записей равно 400, я делаю один INSERT SELECT, чтобы переместить строки в таблицу на диске, затем я делаю DELETE * из таблицы памяти. Я рассчитываю каждую часть. Sqlite3 оптимизирует DELETE *, когда у него нет предложения WHERE, так что это похоже на удаление и повторное создание таблицы, и это очень быстро, менее чем за сотую долю секунды. Это только INSERT SELECT из таблицы памяти в таблицу дисков, скорость которой уменьшается каждый раз. Этот запрос начинается примерно с 0,1 секунды, и после каждой вставки пакета из 400 записей на запрос уходит примерно от 0,1 до 0,2 секунды дольше, чем до последнего, пока в итоге не потребуется несколько секунд, чтобы переместить 400 строк из памяти в диск каждый раз.

Обновление 3: Вот мои операторы создания таблиц и оператор, который я использую для перемещения записей из памяти на диск. Там нет ключей вообще. И да, мой sqlite настроен так, что временная таблица находится в памяти, а не на диске.

Временная таблица в памяти:

  1. CREATE TEMPORARY TABLE allSongsTemp (title TEXT, songId TEXT, artist TEXT, album TEXT, genre TEXT, coverArtId TEXT, path TEXT, suffix TEXT, transcodedSuffix TEXT, duration INTEGER, bitRate INTEGER, track INTEGER, year INTEGER, size INTEGER);

Таблица на диске:

  1. CREATE TABLE allSongsUnsorted (title TEXT, songId TEXT, artist TEXT, album TEXT, genre TEXT, coverArtId TEXT, path TEXT, suffix TEXT, transcodedSuffix TEXT, duration INTEGER, bitRate INTEGER, track INTEGER, year INTEGER, size INTEGER);

Запросы на сброс записей памяти на диск:

  1. INSERT INTO allSongsUnsorted SELECT * FROM allSongsTemp;

  2. DELETE * FROM allSongsTemp;

Запрос, который каждый раз занимает все больше и больше времени, равен # 3, INSERT SELECT. DELETE занимает около 1/100 секунды каждый раз.

Ответы [ 3 ]

0 голосов
/ 26 сентября 2011

Как выглядят ваши ключи, и есть ли у вас какие-то уникальные столбцы / ограничения в этой таблице? Определение (с измененными именами столбцов, если настоящие имена слишком откровенны) поможет диагностировать проблему, но я предполагаю, что где-то в определении таблицы будет скрытное ограничение.

0 голосов
/ 05 октября 2011

Ларри Люстиг назвал это в комментариях к вопросу, но, похоже, больше не может найти ответ.

Удаление и воссоздание таблицы вместо выполнения DELETE * сделали свое дело.Кажется, что, хотя удаление было быстрым, оно вызывало некоторую фрагментацию в памяти, которая замедляла каждое последующее чтение.Если я не прочитал документы sqlite3, DELETE * должен быть оптимизирован как DROP; CREATE;, но, похоже, это не совсем так для временных таблиц памяти (или, возможно, даже таблиц файловой системы, но мне нужно проверить этоубедитесь, что эта проблема может повлиять только на таблицы памяти).

0 голосов
/ 26 сентября 2011

Читайте о транзакциях, и почему вы должны их использовать. Если вы делаете отдельные вставки, то каждая вставка должна проходить цикл начала / конца транзакции со значительными накладными расходами. При массовых операциях вставки / обновления всегда сначала запускайте транзакцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...