База данных 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 max, и, насколько я могу судить, в моей базе данных нет ничего близкого к ним.

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

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

7 ответов


несколько вещей, чтобы рассмотреть:

  • файлы БД 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, которую я использую как постоянное хранилище для основных данных и которая вызвала следующую ошибку при сохранении:

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


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

#!/bin/bash

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

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

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

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

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


чтобы избежать получения "база данных или диск заполнен" в первую очередь, попробуйте это, если у вас много ОЗУ:

sqlite> pragma temp_store = 2;

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

Если вы не получил много ОЗУ, попробуйте это:

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

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


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

Safley копировать s SQLite db

безопасное копирование базы данных 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

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


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

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)