База данных или диск SQLite3 заполнены / образ диска базы данных искажен
Моя база данных составляет около 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, чтобы исправить.
10 ответов
Несколько вещей для рассмотрения:
Файлы БД SQLite3 увеличиваются примерно в несколько раз по размеру страницы БД и не уменьшаются, если вы не используете
VACUUM
, Если вы удалите несколько строк, освободившееся пространство будет помечено внутри и повторно использовано в последующих вставках. Поэтому вставка часто не приводит к изменению размера файла резервной БД.Не следует использовать традиционные инструменты резервного копирования для SQLite (или любой другой базы данных, в этом отношении), поскольку они не учитывают информацию о состоянии БД, которая является критической для обеспечения целостности базы данных. В частности, копирование файлов БД в середине транзакции вставки - это путь к катастрофе...
SQLite3 имеет API специально для резервного копирования или копирования используемых баз данных.
И да, кажется, что ваши файлы БД повреждены. Это может быть ошибка оборудования / файловой системы. Или, возможно, вы скопировали их, когда они были в использовании? Или, может быть, восстановили резервную копию, которая не была правильно сделана?
Для восстановления поврежденной базы данных вы можете использовать утилиту командной строки 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, "образ диска базы данных искажен"}
Я использую следующий скрипт для восстановления искаженных файлов sqlite:
#!/bin/bash
cat <( sqlite3 "$1" .dump | grep "^ROLLBACK" -v ) <( echo "COMMIT;" ) | sqlite3 "fix_$1"
В большинстве случаев, когда база данных sqlite искажена, все еще можно создать дамп. Этот дамп - это в основном много операторов SQL, которые перестраивают базу данных.
Некоторые строки могут отсутствовать в дампе (возможно, потому что они повреждены). В этом случае операторы INSERT для пропущенных строк будут заменены некоторыми комментариями, а сценарий завершится транзакцией ROLLBACK.
Итак, что мы делаем здесь, мы делаем дамп (искаженные строки исключены) и заменяем ROLLBACK на COMMIT, чтобы весь сценарий дамп был зафиксирован вместо отката.
Этот метод спас мою жизнь пару раз уже 100 раз \o/
Чтобы избежать "базы данных или диска переполнен", попробуйте это, если у вас много оперативной памяти:
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), так что будьте осторожны при использовании этого в коде.
У меня сработало клонирование текущей базы данных из командной строки sqlite3.
.open /path/to/database/corrupted_database.sqlite3
.clone /path/to/database/new_database.sqlite3
В файле настроек Django измените имя базы данных
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'new_database.sqlite3'),
}}
Я видел, как это происходит, когда база данных повреждена, вы пытались клонировать ее в новую?
Копия 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;
Это даст вам хорошую чистую резервную копию, которая обязательно будет в правильном состоянии, поскольку запись в базу данных на полпути в процессе копирования невозможна.
При использовании 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
после этого это наконец заработало.
Во время разработки приложения я обнаружил, что сообщения приходят от частых и массовых операций INSERT и UPDATE. Убедитесь, что 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)
У меня было «изображение диска базы данных искажено», пытаясь прочитать БД с определениями объектов, созданными в более поздней версии lib и не поддерживаемыми текущей.
Я полагаю, что может быть много примеров этого, в моем случае это был столбец GENERATED ALWAYS AS - это вызывало ошибку «образ диска базы данных искажен» с версией lib 3.24.0. Обновление до версии 3.37.0, которая поддерживает эту функцию, устранило эту проблему.
Похоже, вы получаете доступ к файлу SQLITE из системы, где файл заблокирован, и приложение, использующее этот файл, не позволяет читать файл. Если вы попытаетесь скопировать файл в другое место, он будет искажен и его нельзя будет использовать.