2012-10-03 7 views
6

내가 로컬 SQLite 데이터베이스를SQLite - SQLite 데이터베이스에서 데이터를 읽는 가장 빠른 방법은 무엇입니까?

표 세부

-- Describe PREFIX_LIST 
CREATE TABLE PREFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY) 

-- Describe SUFFIX_LIST 
CREATE TABLE SUFFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY) 

-- Describe VALID_LIST 
CREATE TABLE VALID_LIST (
    "PART1" TEXT, 
    "PART2" TEXT, 
    PRIMARY KEY(PART1, PART2) 
) 

이 지금이 목록은 정말 거대하다, 나는 그것에서 데이터를 저장해야 할 필요가있다.

여기가 제 구현입니다.

SQLiteConnection con = null; 
SQLiteCommand cmd = null; 
Connect(DbPath, ref con, ref cmd); 

cmd.CommandText = 
    "SELECT PART1 || '@' || PART2 FROM VALID_LIST 
WHERE NOT EXISTS 
    (SELECT * FROM PREFIX_LIST WHERE VALID_LIST.PART1 LIKE '%' || ITEM || '%') 
    AND NOT EXISTS 
    (SELECT * FROM SUFFIX_LIST WHERE VALID_LIST.PART2 LIKE '%' || ITEM || '%')"; 

var reader = cmd.ExecuteReader(); 

if (reader.HasRows) 
{ 
    string savePath; 

    if (SaveTextFile(out savePath) == DialogResult.OK) 
    { 
     TextWriter writer = new StreamWriter(savePath); 
     while (reader.Read()) 
     { 
      writer.WriteLine(reader.GetString(0)); 
     } 
     writer.Close(); 
     writer.Dispose(); 
    } 

} 

reader.Close(); 
reader.Dispose(); 
cmd.Dispose(); 
con.Close(); 
con.Dispose(); 

MessageBox.Show("List Saved!.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); 

목록을 더 빨리 저장할 수있는 더 나은 방법이 필요합니다. VALID_LIST에서 총 항목은 2,639,117

이며 위의 SQL 쿼리에 대한 저장 15 분이 걸렸다!

SQL 쿼리를 최적화 할 수 있으면 알려주십시오! LIKE

+2

상관 관계가있는 하위 쿼리 +'LIKE' = 거대한 실적이 – cdhowie

+0

@cdhowie - 맞습니다.하지만 다른 해결책은 무엇입니까? 나는 쿼리가 어떻게 든 최적화되어야한다고 생각합니다! –

+0

스키마를 완전히 변경하지 않고 이것을 최적화하는 쉬운 방법이 없다고 생각합니다. – cdhowie

답변

6

쿼리 미리

덕분에 와일드 카드가 접미사에 연결되어 있지 않으면 일반적으로 매우 느린 것입니다. LIKE '%foo'과 같은 술어는 일반적인 문자열 색인화를 통해 색인화 될 수 없습니다.

그러나 full text search (FTS) 기능을 사용하면 sqlite의 무거운 LIKE 사용을 대체 할 수 있습니다.

FTS3 및 FTS4 확장 모듈은 사용자가 특수 테이블을 만들 수있는 내장 (이하 "FTS 테이블") 전체 텍스트 인덱스입니다. 전체 텍스트 인덱스를 사용하면 에 대해 하나 이상의 단어 (이하 "토큰")가 포함 된 모든 행을 데이터베이스에 효율적으로 쿼리 할 수 ​​있습니다. 테이블에 여러 개의 큰 문서가 포함되어 있어도 마찬가지입니다.

그들은 an example으로 유스 케이스의 성능 측면에서 유망 해 보입니다.

CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT);  /* FTS3 table */ 
CREATE TABLE enrondata2(content TEXT);      /* Ordinary table * 

SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux'; /* 0.03 seconds */ 
SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */ 
+0

전제가 있습니다. 접두사는 색인을 사용할 수 있지만 접미사는 사용할 수 없습니다. – cdhowie

+0

@cdhowie 나는 동의한다, 나는 와일드 카드가 부착 된 곳을 언급하고 있었다. 나는 나의 대답을 분명히했다. –

+0

당신이 지금 무엇을 의미하는지 봅니다. 명확히하기 위해 다소 모호했습니다. – cdhowie

2

전체 텍스트 검색 사용을 고려하십시오.

PREFIX 및 SUFFIX의 값은 토큰 화되어야하며 (별도의 단어 여야 함) 일치시키려는 항목은이 값 중 하나의 고유 토큰이어야합니다 (부분이 아님). 한 단어 또는 두 단어 합쳐서). 예를 들어 PREFIX 및 SUFFIX의 문자열은 'RED BLUE GREEN'또는 'DOG, CAT, CAPYBARA'와 같아야하며 ITEM 값은 RED, BLUE, GREEN, DOG, CAT 또는 CAPYBARA 여야합니다.

이러한 조건이 충족되면 전체 텍스트 검색을 활성화하고 이러한 테이블을 전체 텍스트 테이블로 다시 만들고 LIKE (와일드 카드)를 MATCH로 바꿀 수 있습니다. 이 경우 SQLite는 토큰에있는 인덱스를 PREFIX 또는 SUFFIX에서 찾을 수 있으며 검색 부분은 훨씬 빠릅니다.

불행히도, SQlite에서 FTS를 활성화하는 것은 하나 이상의 컴파일 타임 플래그가 설정된 소스 코드에서 제품을 컴파일하는 것과 관련이 있습니다. 나는이 경험이 없다.

+0

thnx 모든 정보! 비록 내가 느린이라도 내 솔루션 atm을 고수해야만하는 것처럼 보입니다! –

+0

일치하는 항목이 개별 단어에 대해 사실입니까? 그렇다면 단어를 한 번에 하나씩 자신의 행에 넣으십시오. 그 일을 매우 빨리 할 수 ​​있습니다. –

+0

죄송합니다, 내 영어에 대한 죄송하지만 SQL을 통해 할 노력하고있어, valid_list.part1 내 모든 항목을 부분적으로 prefix_list.item에있는 모든 항목에서 일치하는지 확인하십시오 –

0

필자가 원하는지 확실하지 않지만 쓰기 프로세스 속도를 높이는 데 도움이 될 것입니다. 데이터베이스에서 읽은 문자열을 문자열 작성기에 축적 한 다음 파일에 기록하십시오. 예를 들어 100k 문자열을 읽은 다음 100k 문자열을 한 번에 파일에 쓸 수 있습니다.

StringBuilder builder = new StringBuilder(); 
    int count = 0; //to limit the number of rows stored in string builder. 
    while (reader.Read()) 
    { 

     builder.AppendLine(reader.GetString(0)); 
     count++; 

     //store every 100k or so rows at once. 
     //This number depends on how much RAM 
     //you can allocate towards storing the string of rows. 
     //If you have 2GB of free RAM 
     //this number can easily be 1 million but it always depends on the 
     //size of each string stored in database. 
     if(count == 100000) 
     { 
      File.AppendAllText(path, builder.ToString()); //Append all rows to the file 
      builder.Clear(); //clear the string for next 100k rows of data 
      count = 0; //Clear the counter value 
     } 
     count++ 
    } 

도움이되었는지 알려주십시오.

관련 문제