База данных или диск SQLite3 заполнены / образ диска базы данных искажен - PullRequest
47 голосов
/ 11 марта 2011

Моя база данных составляет около 25 МБ, и я проверил, что имя пользователя, к которому она обращается, а также права доступа к файлам не менялись в течение нескольких месяцев. У меня возникла проблема, когда запросы не выполняются из-за «базы данных или диск заполнен», а затем иногда возникает проблема «Образ диска базы данных поврежден».

Если я не читаю это неправильно, мой диск почти не заполнен (это сервер Ubuntu, 9.10, если это что-то меняет)

Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             19610300   2389596  16224560  13% /
udev                     10240       128     10112   2% /dev
none                    254136         0    254136   0% /dev/shm
none                    254136        36    254100   1% /var/run
none                    254136         0    254136   0% /var/lock
none                    254136         0    254136   0% /lib/init/rw

В качестве теста я просто выполнил действие, которое добавило новую запись, и это нормально. Я пытаюсь выяснить, есть ли определенный набор действий, которые терпят неудачу. Однако после вставки (и проверки ее наличия) количество байтов на диске для базы данных не изменилось (ни вверх, ни вниз).

Использование утилиты командной строки приводит к чему-то похожему на следующее, что не дает впечатляющий эффект:)

SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> pragma integrity_check;
*** in database main ***
On tree page 2 cell 0: 2nd reference to page 26416
On tree page 2 cell 1: 2nd reference to page 26417
On tree page 2 cell 2: 2nd reference to page 26434
On tree page 2 cell 3: 2nd reference to page 26449
On tree page 2 cell 4: 2nd reference to page 26464
On tree page 2 cell 5: 2nd reference to page 26358
On tree page 2 cell 6: 2nd reference to page 26494
On tree page 2 cell 7: Child page depth differs
On tree page 2 cell 8: 2nd reference to page 26190
On tree page 2 cell 8: Child page depth differs

... etc., etc. ...

Любые идеи о том, где я должен искать дальше? Есть ли проблема с максимальным количеством строк в таблице или чем-то? Я немного читал о максимальных значениях SQLite3, и, насколько я могу судить, в моей базе данных нет ничего похожего на них.

Затем я посмотрел на свои ежедневные резервные копии и вижу, что резервная копия базы данных не менялась в размере файла в течение 3-4 дней - очень странно. Я восстановил резервную копию базы данных до того, как она не изменилась в размере файла, и все еще получаю странные проблемы.

Я думаю, что мне придется (1) восстановить из более старой резервной копии и (2) перезапустить мои миграции Rails, чтобы исправить.

Ответы [ 7 ]

52 голосов
/ 15 марта 2011

Для восстановления поврежденной базы данных вы можете использовать утилиту командной строки sqlite3. Введите следующие команды в оболочке после установки переменных среды:

cd $DATABASE_LOCATION
echo '.dump'|sqlite3 $DB_NAME|sqlite3 repaired_$DB_NAME
mv $DB_NAME corrupt_$DB_NAME
mv repaired_$DB_NAME $DB_NAME

Этот код помог мне восстановить базу данных SQLite, которую я использую в качестве постоянного хранилища для Core Data и которая вызвала следующую ошибку при сохранении:

Не удалось сохранить: NSError 259 в домене NSCocoaErrorDomain {NSFilePath = mydata.db NSUnderlyingException = Фатальная ошибка. База данных на mydata.db поврежден Код ошибки SQLite: 11, 'образ диска базы данных искажен'}

25 голосов
/ 11 марта 2011

Несколько вещей, на которые следует обратить внимание:

  • Файлы БД SQLite3 увеличиваются примерно в несколько раз по размеру страницы БД и не уменьшаются, если вы не используете VACUUM.Если вы удалите несколько строк, освободившееся пространство будет помечено внутри и повторно использовано при последующих вставках.Поэтому вставка часто не приводит к изменению размера файла резервной БД.

  • Не следует использовать традиционные инструменты резервного копирования для SQLite (или любой другой базы данных, в этом отношении),поскольку они не принимают во внимание информацию о состоянии БД, которая имеет решающее значение для обеспечения целостности базы данных.В частности, копирование файлов БД в середине транзакции вставки - это путь к катастрофе ...

  • SQLite3 имеет API специально для резервного копирования или копированияиспользуемые базы данных.

  • И да, кажется, что ваши файлы БД повреждены .Это может быть ошибка оборудования / файловой системы.Или, может быть, вы скопировали их, когда они были в использовании?Или может быть восстановлена ​​резервная копия, которая не была правильно сделана?

20 голосов
/ 08 апреля 2013

Я использую следующий скрипт для восстановления искаженных файлов sqlite:

#!/bin/bash

cat <( sqlite3 "$1" .dump | grep "^ROLLBACK" -v ) <( echo "COMMIT;" ) | sqlite3 "fix_$1"

В большинстве случаев, когда база данных sqlite искажена, все еще можно создать дамп. Этот дамп - это в основном много операторов SQL, которые перестраивают базу данных.

Некоторые строки могут отсутствовать в дампе (возможно, потому что они повреждены). В этом случае операторы INSERT для пропущенных строк будут заменены некоторыми комментариями, а сценарий завершится транзакцией ROLLBACK.

Итак, мы делаем дамп (искаженные строки исключены) и заменяем ROLLBACK на COMMIT, чтобы весь скрипт дампа был зафиксирован вместо отката.

Этот метод спас мою жизнь пару раз уже 100 раз \ o /

9 голосов
/ 09 октября 2013

Во-первых, чтобы избежать «базы данных или диска переполнено», попробуйте это, если у вас много оперативной памяти:

sqlite> pragma temp_store = 2;

Это говорит SQLite помещать временные файлы в память. (Сообщение «база данных или диск заполнен» не означает, что база данных заполнена или диск заполнен! Это означает, что временный каталог заполнен.) У меня 256 ГБ ОЗУ, но только 2 ГБ / tmp, так что это работает отлично подходит для меня. Чем больше у вас ОЗУ, тем больше файлов базы данных вы можете использовать.

Если у вас мало барана, попробуйте это:

sqlite> pragma temp_store = 1;
sqlite> pragma temp_store_directory = '/directory/with/lots/of/space';

temp_store_directory устарела (что глупо, поскольку temp_store не устарела и требует temp_store_directory), поэтому будьте осторожны при использовании этого в коде.

5 голосов
/ 11 марта 2011

Я видел, как это происходило, когда база данных была повреждена. Вы пытались клонировать ее в новую?

Копия Safley с базой данных SQLite

Безопасное копирование базы данных SQLite

Тривиально легко скопировать базу данных SQLite. Это менее тривиально это таким образом, что это не повредит. Вот как это сделать:

shell$ sqlite3 some.db
sqlite> begin immediate;
<press CTRL+Z>
shell$ cp some.db some.db.backup
shell$ exit
sqlite> rollback;

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

1 голос
/ 11 марта 2014

при использовании Google App Engine у ​​меня возникла эта проблема.По какой-то причине я делал следующее с тех пор, как Google App Engine никогда не запускался.

$ echo '' > /tmp/appengine.apprtc.root/*.db

Чтобы исправить это, я должен был сделать это вручную:

$ sqlite3 datastore.db
sqlite> begin immediate;
<press CTRL+Z>
$ cp datastore.db logs.db

А затем запустить Google App Engine сфлаг:

$ dev_appserver.py --clear_datastore --clear_search_index

после этого он наконец заработал.

0 голосов
/ 18 августа 2017

Во время разработки приложения я обнаружил, что сообщения приходят от частых и массовых операций INSERT и UPDATE. Убедитесь, что вставили и обновили несколько строк или данных за одну операцию.

var updateStatementString : String! = ""

for item in cardids {
    let newstring = "UPDATE "+TABLE_NAME+" SET pendingImages = '\(pendingImage)\' WHERE cardId = '\(item)\';"
    updateStatementString.append(newstring)
}

print(updateStatementString)

let results = dbManager.sharedInstance.update(updateStatementString: updateStatementString)

return Int64(results)
...