2014-03-28 5 views
1

DELETE 쿼리는 간단하다sqlite에서 DELETE 중 잠금을 피하는 방법은 무엇입니까?

DELETE FROM pages WHERE status = 0 

그것은 (20K 행 ~ 제거) 완료하는 데 약 15 분 정도 소요됩니다. 로컬 파일 시스템을 매핑하는 약 500MB의 데이터베이스이며 약 3 백만 개의 레코드가 들어 있습니다.

구조 :

  • pages - 몇 가지 기록
  • files - 약 3 백만 기록 - 약 23 만 기록은 pages
  • meta에서 열을 참조 ON DELETE CASCADE와 외래 키 제약 조건을 포함 ON DELETE CASCADE 인 외래 키 제약 조건을 포함하며 참조 열은 filespages
  • 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로 설정하고 동기화를 끄면 조금 더 빨리 실행되지만 너무 위험합니다.

긴 쓰기 잠금을 피하기 위해 나는 0.5 초 간격으로 한 번에 40 레코드를 삭제하려고했습니다. 하지만 이로 인해 전체 프로세스가 10 배까지 느려집니다.

속도를 향상시키고 잠금을 피할 수있는 다른 방법이 있습니까?


추 신 : INSERT가 훨씬 빠르다는 것이 나에게는 당황 스럽습니다. 삭제하는 레코드의 양을 삽입하는 데 2 ​​분이 걸리며 그 시간에는 많은 파일 처리 (Exif가 많은 이미지에서 읽음)가 포함됩니다. 레코드를 삽입하는 것보다 느리게 제거하는 이유는 무엇입니까?

+0

제안하면 하드 삭제보다는 소프트 삭제를 사용하십시오. 단점은 코드가 변경되어 저장 용량이 증가 할 수 있습니다. – Rippo

+0

데이터베이스 스키마 (인덱스 포함)? –

+0

@CL : [스키마] (http://sqlfiddle.com/#!5/39c70),하지만 sqlfiddle에서 작동하지 않는 것처럼 인덱스와 fts 테이블을 주석 처리해야했습니다.부드러운 삭제로 ​​레코드를 SELECT 쿼리에서 고려해서는 안되는 값으로 레코드를 업데이트한다는 의미입니까? 이것이 내가하고있는 일이지만, 여전히 백그라운드 프로세스에서 죽은 레코드를 제거하고 싶습니다. 문제는 프로세스가 일부 테이블을 잠그고 수행하는 작업에 너무 오래 걸리는 것입니다. –

답변

2

테이블의 gallery 열에 인덱스가 없기 때문에 pages에서 삭제하는 속도가 느립니다. pages 레코드가 실제로 삭제 될 때마다 데이터베이스는 ON DELETE CASCADE 제약 조건과 일치하는 모든 meta 레코드를 검색해야합니다. 이로 인해 모든 삭제 된 레코드에 대해 전체 테이블이 검색됩니다.

(그런 검사가 이루어지지해야하기 때문에 인서트는 빠릅니다.)

SQLite는이 동시성을 위해 설계되지 않았습니다; 동시에 여러 작가를 가질 수는 없습니다. 그러나 라이터와 동시에 여러 독자를 허용하려면 write-ahead logging을 사용하도록 설정하십시오.

+0

나는 'metaFileId' 인덱스를 사용할 것이라고 생각했습니다. 어쨌든 갤러리 열에 대한 색인을 추가하기 전에 "explain query plan"을 수행했으며 실제로 메타에 대해 SCAN을 수행했습니다. 이제 EXPLAIN QUERY PLAN이 새로운 인덱스를 사용하고 있다고 알려주지 만 쿼리는 이전처럼 느려집니다. ( –

+0

ok 문제는 제약이있는'hero' 열의 누락 된 인덱스였습니다 :) 'meta.gallery' 칼럼은 삭제 된 페이지 레코드 당 단 하나의 스캔 만했기 때문에 큰 차이를 만들지 않았습니다. 그것은 db에 대해 +2 초와 같기 때문에 나는 그걸로 살 수 있습니다. 하지만 네가 옳았 어. 도와 줘서 고마워! EXPLAIN QUERY PLAIN이 계단식 삭제에 대한 검색/스캔 작업과 같은 추가 정보를 제공했으면 좋겠습니다. –