SQLite3数据库或磁盘已满/数据库磁盘映像格式错误

时间:2011-03-11 14:34:03

标签: file sqlite filesystems corruption

我的数据库大约是25 MB,我已经确认访问它的用户名以及文件权限在几个月内没有变化。我遇到问题,由于“数据库或磁盘已满”,查询失败,有时“数据库磁盘映像格式错误”问题。

除非我读错了,否则我的磁盘不会接近满(这是一个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迁移来修复。

8 个答案:

答案 0 :(得分:50)

要修复损坏的数据库,您可以使用sqlite3命令行实用程序。在设置环境变量后,在shell中键入以下命令:

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,   '数据库磁盘映像格式错误'}

答案 1 :(得分:24)

需要考虑的一些事项:

  • SQLite3数据库文件大致增长到数据库页面大小的倍数,除非使用VACUUM,否则不会收缩。如果删除某些行,则释放的空间将在内部标记,并在以后的插入中重复使用。因此,插入通常不会导致后备DB文件的大小发生变化。

  • 您不应该为SQLite(或任何其他数据库)使用传统备份工具,因为它们没有考虑对确保数据库未损坏至关重要的数据库状态信息。特别是,在插入事务中复制数据库文件是灾难的一个方法......

  • SQLite3有API专门用于备份或复制正在使用的数据库。

  • 是的,您的数据库文件似乎是corrupted。它可能是硬件/文件系统错误。或许你在使用它们时复制它们?或者可能还原了未正确使用的备份?

答案 2 :(得分:18)

我使用以下脚本修复格式错误的sqlite文件:

#!/bin/bash

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

大多数情况下,当sqlite数据库格式错误时,仍然可以进行转储。这个转储基本上是很多重建数据库的SQL语句。

转储中可能缺少某些行(可能是因为它们已损坏)。如果是这种情况,缺失行的INSERT语句将被替换为一些注释,脚本将以ROLLBACK TRANSACTION结束。

所以我们在这里做的是我们进行转储(排除格式错误的行),然后用COMMIT替换ROLLBACK,以便提交整个转储脚本而不是回滚。

这种方法已经为我的生命节省了几百次\ o /

答案 3 :(得分:9)

为了避免首先“数据库或磁盘已满”,如果你有大量的RAM,请尝试这样做:

sqlite> pragma temp_store = 2;

告诉SQLite将临时文件放在内存中。 (“数据库或磁盘已满”消息并不意味着数据库已满或磁盘已满!这意味着临时目录已满。)我有256G的RAM但只有2G的/ tmp,所以这是有效的对我很好。您拥有的RAM越多,您可以使用的db文件就越大。

如果你没有很多公羊,试试这个:

sqlite> pragma temp_store = 1;
sqlite> pragma temp_store_directory = '/directory/with/lots/of/space';
不推荐使用

temp_store_directory(这很愚蠢,因为temp_store不被弃用且需要temp_store_directory),所以要小心在代码中使用它。

答案 4 :(得分:5)

我已经看到当数据库损坏时会发生这种情况,您是否尝试将其克隆到新数据库中?

Safley copy a 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;
     

这将为您提供一个很好的干净备份,肯定是正确的   状态,因为通过复制中途写入数据库   过程是不可能的。

答案 5 :(得分:3)

从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'),
}}

答案 6 :(得分:1)

在使用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
之后,它终于奏效了。

答案 7 :(得分:0)

在应用程序开发期间,我发现消息来自频繁且大量的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)