刪除查詢很簡單:如何避免在sqlite 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秒的延遲。但是這會減慢整個過程甚至10x
有沒有其他方法可以提高速度和/或避免鎖定? PS:讓我感到困惑的是INSERTs要快得多。插入我正在刪除的記錄數量需要2分鐘,並且該時間包括一些繁重的文件處理(Exif從大量圖像中讀取)。爲什麼刪除記錄比插入慢?
建議,使用軟刪除而不是硬刪除。下行是代碼變化,可能會增加存儲量。 – Rippo
數據庫模式(包括索引)? –
@CL:[schema](http://sqlfiddle.com/#!5/39c70),但我不得不註釋一個索引和fts表,因爲它似乎不能在sqlfiddle上工作。通過軟刪除,你的意思是更新記錄的值,這表明記錄不應該在SELECT查詢中考慮?這就是我正在做的,但我仍然想要在後臺進程中刪除死亡記錄。問題是這個進程鎖定了一些表,並且它花費的時間太長了 –