【发布时间】:2014-05-08 14:03:53
【问题描述】:
DELETE 查询很简单:
DELETE FROM pages WHERE status = 0
大约需要 15 分钟才能完成(删除约 20K 行)。这是一个约 500 MB 的数据库,映射本地文件系统,包含大约 300 万条记录。
结构:
-
pages- 几条记录 -
files- 大约 230K 条记录,包含带有ON DELETE CASCADE的外键约束,它引用来自pages的列 -
meta- 大约 300 万条记录,包含带有ON DELETE CASCADE的外键约束,它引用来自files和pages的列 -
search- FTS4 表,与meta几乎完全相同。该表的完整性由触发器维护。
CREATE TABLE pages(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT,
name TEXT NOT NULL,
type INTEGER NOT NULL DEFAULT 1,
data TEXT,
parent INTEGER,
status INTEGER DEFAULT 1,
comments INTEGER DEFAULT 1,
priority INTEGER DEFAULT 0,
UNIQUE(slug),
FOREIGN KEY(parent) REFERENCES pages(id) ON DELETE CASCADE
);
CREATE INDEX "pageParent" ON "pages"("parent");
CREATE TABLE files(
id INTEGER PRIMARY KEY AUTOINCREMENT,
gallery INTEGER NOT NULL,
type INTEGER NOT NULL DEFAULT 1,
sPath TEXT,
rPath TEXT,
parent INTEGER,
hero INTEGER,
hidden INTEGER DEFAULT 0,
createdAt DATETIME,
mTime TEXT,
UNIQUE(sPath),
FOREIGN KEY(gallery) REFERENCES pages(id) ON DELETE CASCADE,
FOREIGN KEY(parent) REFERENCES files(id) ON DELETE CASCADE,
FOREIGN KEY(hero) REFERENCES files(id) ON DELETE SET NULL
);
CREATE INDEX "fileGallery" ON "files"("gallery");
CREATE INDEX "fileType" ON "files"("type");
CREATE INDEX "fileParent" ON "files"("parent");
CREATE INDEX "fileRPathNS" ON "files"("rPath" COLLATE NATSORT);
CREATE TABLE thumbs(
hash TEXT,
image INTEGER,
width INTEGER,
height INTEGER,
FOREIGN KEY(image) REFERENCES files(id) ON DELETE CASCADE,
PRIMARY KEY(hash, image) ON CONFLICT REPLACE
);
CREATE INDEX "thumbImage" ON "thumbs"("image");
CREATE TABLE meta(
id INTEGER PRIMARY KEY AUTOINCREMENT,
file INTEGER NOT NULL,
key TEXT NOT NULL,
value TEXT,
extra TEXT,
gallery INTEGER,
FOREIGN KEY(gallery) REFERENCES pages(id) ON DELETE CASCADE,
FOREIGN KEY(file) REFERENCES files(id) ON DELETE CASCADE
);
CREATE INDEX "metaFileId" ON "meta"("file");
CREATE INDEX "metaKey" ON "meta"("key");
CREATE INDEX "metaExtra" ON "meta"("extra");
CREATE VIRTUAL TABLE search USING fts4(file, key, value, gallery);
CREATE TRIGGER metaBeforeUpd BEFORE UPDATE ON meta BEGIN
DELETE FROM search WHERE docid = OLD.rowid;
END;
CREATE TRIGGER metaBeforeDel BEFORE DELETE ON meta BEGIN
DELETE FROM search WHERE docid = OLD.rowid;
END;
CREATE TRIGGER metaAfterUpd AFTER UPDATE ON meta BEGIN
INSERT INTO search(docid, file, key, value, gallery) VALUES(NEW.rowid, NEW.file, NEW.key, NEW.value, NEW.gallery);
END;
CREATE TRIGGER metaAfterIns AFTER INSERT ON meta BEGIN
INSERT INTO search(docid, file, key, value, gallery) VALUES(NEW.rowid, NEW.file, NEW.key, NEW.value, NEW.gallery);
END;
问题在于它不仅速度慢,而且还锁定了这些表,所以在此期间我无法对它们进行任何更改。
我尝试了来自this question and answers 的所有建议,但没有显着改进。将日记模式设置为 MEMORY 并关闭同步可以让它运行得更快一些,但风险太大。
为了避免长时间的写锁,我尝试逐步删除记录,一次删除 40 条记录,中间有 0.5 秒的延迟。但这会使整个过程减慢 10 倍
还有其他方法可以提高速度和/或避免锁定吗?
PS:让我感到困惑的是 INSERT 的速度要快得多。插入我要删除的记录数量需要 2 分钟,并且该时间包括一些繁重的文件处理(Exif 从大量图像中读取)。为什么删除记录比插入慢?
【问题讨论】:
-
建议,使用软删除而不是硬删除。缺点是代码更改,可能会增加存储量。
-
数据库架构(包括索引)?
-
@CL:the schema,但我不得不注释掉索引和 fts 表,因为它似乎不适用于 sqlfiddle。通过软删除,您的意思是使用表明不应在 SELECT 查询中考虑记录的值更新记录?这就是我正在做的事情,但我仍然想在后台进程中删除死记录。问题是该进程锁定了一些表,并且它所做的事情花费了太长时间
标签: performance sqlite cascading-deletes sql-delete